agent-relay 2.3.11 → 2.3.13
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/install.sh +32 -0
- package/package.json +21 -21
- package/packages/acp-bridge/package.json +2 -2
- package/packages/bridge/package.json +7 -7
- package/packages/broker-sdk/README.md +32 -0
- package/packages/broker-sdk/dist/__tests__/unit.test.js +70 -2
- package/packages/broker-sdk/dist/__tests__/unit.test.js.map +1 -1
- package/packages/broker-sdk/dist/client.d.ts +2 -0
- package/packages/broker-sdk/dist/client.d.ts.map +1 -1
- package/packages/broker-sdk/dist/client.js +10 -0
- package/packages/broker-sdk/dist/client.js.map +1 -1
- package/packages/broker-sdk/dist/protocol.d.ts +4 -0
- package/packages/broker-sdk/dist/protocol.d.ts.map +1 -1
- package/packages/broker-sdk/dist/relay.d.ts +10 -0
- package/packages/broker-sdk/dist/relay.d.ts.map +1 -1
- package/packages/broker-sdk/dist/relay.js +53 -0
- package/packages/broker-sdk/dist/relay.js.map +1 -1
- package/packages/broker-sdk/dist/relaycast.d.ts +10 -0
- package/packages/broker-sdk/dist/relaycast.d.ts.map +1 -1
- package/packages/broker-sdk/dist/relaycast.js +40 -0
- package/packages/broker-sdk/dist/relaycast.js.map +1 -1
- package/packages/broker-sdk/dist/workflows/coordinator.d.ts +1 -0
- package/packages/broker-sdk/dist/workflows/coordinator.d.ts.map +1 -1
- package/packages/broker-sdk/dist/workflows/coordinator.js +239 -7
- package/packages/broker-sdk/dist/workflows/coordinator.js.map +1 -1
- package/packages/broker-sdk/dist/workflows/index.d.ts +1 -0
- package/packages/broker-sdk/dist/workflows/index.d.ts.map +1 -1
- package/packages/broker-sdk/dist/workflows/index.js +1 -0
- package/packages/broker-sdk/dist/workflows/index.js.map +1 -1
- package/packages/broker-sdk/dist/workflows/run.d.ts +3 -1
- package/packages/broker-sdk/dist/workflows/run.d.ts.map +1 -1
- package/packages/broker-sdk/dist/workflows/run.js +4 -0
- package/packages/broker-sdk/dist/workflows/run.js.map +1 -1
- package/packages/broker-sdk/dist/workflows/runner.d.ts +9 -0
- package/packages/broker-sdk/dist/workflows/runner.d.ts.map +1 -1
- package/packages/broker-sdk/dist/workflows/runner.js +203 -14
- package/packages/broker-sdk/dist/workflows/runner.js.map +1 -1
- package/packages/broker-sdk/dist/workflows/trajectory.d.ts +80 -0
- package/packages/broker-sdk/dist/workflows/trajectory.d.ts.map +1 -0
- package/packages/broker-sdk/dist/workflows/trajectory.js +362 -0
- package/packages/broker-sdk/dist/workflows/trajectory.js.map +1 -0
- package/packages/broker-sdk/dist/workflows/types.d.ts +15 -1
- package/packages/broker-sdk/dist/workflows/types.d.ts.map +1 -1
- package/packages/broker-sdk/package.json +2 -2
- package/packages/broker-sdk/src/__tests__/swarm-coordinator.test.ts +356 -0
- package/packages/broker-sdk/src/__tests__/unit.test.ts +92 -1
- package/packages/broker-sdk/src/__tests__/workflow-trajectory.test.ts +408 -0
- package/packages/broker-sdk/src/client.ts +15 -0
- package/packages/broker-sdk/src/protocol.ts +5 -0
- package/packages/broker-sdk/src/relay.ts +59 -0
- package/packages/broker-sdk/src/relaycast.ts +42 -0
- package/packages/broker-sdk/src/workflows/README.md +64 -0
- package/packages/broker-sdk/src/workflows/coordinator.ts +246 -8
- package/packages/broker-sdk/src/workflows/index.ts +1 -0
- package/packages/broker-sdk/src/workflows/run.ts +9 -1
- package/packages/broker-sdk/src/workflows/runner.ts +249 -14
- package/packages/broker-sdk/src/workflows/schema.json +13 -1
- package/packages/broker-sdk/src/workflows/trajectory.ts +507 -0
- package/packages/broker-sdk/src/workflows/types.ts +31 -1
- package/packages/broker-sdk/tsconfig.json +1 -0
- package/packages/broker-sdk/vitest.config.ts +9 -0
- package/packages/config/package.json +2 -2
- package/packages/continuity/package.json +2 -2
- package/packages/daemon/package.json +12 -12
- package/packages/hooks/package.json +4 -4
- package/packages/mcp/package.json +5 -5
- package/packages/memory/package.json +2 -2
- package/packages/policy/package.json +2 -2
- package/packages/protocol/package.json +1 -1
- package/packages/resiliency/package.json +1 -1
- package/packages/sdk/package.json +3 -3
- package/packages/sdk-py/src/agent_relay/builder.py +4 -0
- package/packages/sdk-py/src/agent_relay/types.py +15 -0
- package/packages/spawner/package.json +1 -1
- package/packages/state/package.json +1 -1
- package/packages/storage/package.json +2 -2
- package/packages/telemetry/package.json +1 -1
- package/packages/trajectory/package.json +2 -2
- package/packages/user-directory/package.json +2 -2
- package/packages/utils/package.json +3 -3
- package/packages/wrapper/package.json +5 -5
|
@@ -173,6 +173,8 @@ verification:
|
|
|
173
173
|
|
|
174
174
|
The `swarm.pattern` field controls how agents are coordinated:
|
|
175
175
|
|
|
176
|
+
### Core Patterns
|
|
177
|
+
|
|
176
178
|
| Pattern | Description |
|
|
177
179
|
|---------|-------------|
|
|
178
180
|
| `dag` | Directed acyclic graph — steps run based on dependency edges (default) |
|
|
@@ -186,6 +188,68 @@ The `swarm.pattern` field controls how agents are coordinated:
|
|
|
186
188
|
| `debate` | Agents propose and counter-argue |
|
|
187
189
|
| `hierarchical` | Multi-level reporting structure |
|
|
188
190
|
|
|
191
|
+
### Data Processing Patterns
|
|
192
|
+
|
|
193
|
+
| Pattern | Description |
|
|
194
|
+
|---------|-------------|
|
|
195
|
+
| `map-reduce` | Split work into chunks (mappers), process in parallel, aggregate results (reducers) |
|
|
196
|
+
| `scatter-gather` | Fan out requests to workers, collect and synthesize responses |
|
|
197
|
+
|
|
198
|
+
### Supervision & Quality Patterns
|
|
199
|
+
|
|
200
|
+
| Pattern | Description |
|
|
201
|
+
|---------|-------------|
|
|
202
|
+
| `supervisor` | Monitor agent monitors workers, restarts on failure, manages health |
|
|
203
|
+
| `reflection` | Agent produces output, critic reviews and provides feedback for iteration |
|
|
204
|
+
| `verifier` | Producer agents submit work to verifier agents for validation |
|
|
205
|
+
|
|
206
|
+
### Adversarial & Validation Patterns
|
|
207
|
+
|
|
208
|
+
| Pattern | Description |
|
|
209
|
+
|---------|-------------|
|
|
210
|
+
| `red-team` | Attacker agents probe for weaknesses, defender agents respond |
|
|
211
|
+
| `auction` | Auctioneer broadcasts tasks, agents bid based on capability/cost |
|
|
212
|
+
|
|
213
|
+
### Resilience Patterns
|
|
214
|
+
|
|
215
|
+
| Pattern | Description |
|
|
216
|
+
|---------|-------------|
|
|
217
|
+
| `escalation` | Start with fast/cheap agents, escalate to more capable on failure |
|
|
218
|
+
| `saga` | Distributed transactions with compensating actions on failure |
|
|
219
|
+
| `circuit-breaker` | Primary agent with fallback chain, fail fast and recover |
|
|
220
|
+
|
|
221
|
+
### Collaborative Patterns
|
|
222
|
+
|
|
223
|
+
| Pattern | Description |
|
|
224
|
+
|---------|-------------|
|
|
225
|
+
| `blackboard` | Shared workspace where agents contribute incrementally to a solution |
|
|
226
|
+
| `swarm` | Emergent behavior from simple agent rules (neighbor communication) |
|
|
227
|
+
|
|
228
|
+
### Auto-Selection by Role
|
|
229
|
+
|
|
230
|
+
When `swarm.pattern` is omitted, the coordinator auto-selects based on agent roles.
|
|
231
|
+
Patterns are checked in priority order below (first match wins):
|
|
232
|
+
|
|
233
|
+
| Priority | Pattern | Required Roles/Config |
|
|
234
|
+
|----------|---------|----------------------|
|
|
235
|
+
| 1 | `dag` | Steps with `dependsOn` |
|
|
236
|
+
| 2 | `consensus` | Uses `coordination.consensusStrategy` config |
|
|
237
|
+
| 3 | `map-reduce` | `mapper` + `reducer` |
|
|
238
|
+
| 4 | `red-team` | (`attacker` OR `red-team`) + (`defender` OR `blue-team`) |
|
|
239
|
+
| 5 | `reflection` | `critic` |
|
|
240
|
+
| 6 | `escalation` | `tier-1`, `tier-2`, etc. |
|
|
241
|
+
| 7 | `auction` | `auctioneer` |
|
|
242
|
+
| 8 | `saga` | `saga-orchestrator` OR `compensate-handler` |
|
|
243
|
+
| 9 | `circuit-breaker` | `fallback`, `backup`, OR `primary` |
|
|
244
|
+
| 10 | `blackboard` | `blackboard` OR `shared-workspace` |
|
|
245
|
+
| 11 | `swarm` | `hive-mind` OR `swarm-agent` |
|
|
246
|
+
| 12 | `verifier` | `verifier` |
|
|
247
|
+
| 13 | `supervisor` | `supervisor` |
|
|
248
|
+
| 14 | `hierarchical` | `lead` (with 4+ agents) |
|
|
249
|
+
| 15 | `hub-spoke` | `hub` OR `coordinator` |
|
|
250
|
+
| 16 | `pipeline` | Unique agents per step, 3+ steps |
|
|
251
|
+
| 17 | `fan-out` | Default fallback |
|
|
252
|
+
|
|
189
253
|
## Error Handling
|
|
190
254
|
|
|
191
255
|
### Step-Level
|
|
@@ -52,6 +52,7 @@ const PATTERN_HEURISTICS: Array<{
|
|
|
52
52
|
test: (config: RelayYamlConfig) => boolean;
|
|
53
53
|
pattern: SwarmPattern;
|
|
54
54
|
}> = [
|
|
55
|
+
// ── Dependency-based patterns (highest priority) ──────────────────────
|
|
55
56
|
{
|
|
56
57
|
test: (c) =>
|
|
57
58
|
Array.isArray(c.workflows) &&
|
|
@@ -62,15 +63,66 @@ const PATTERN_HEURISTICS: Array<{
|
|
|
62
63
|
test: (c) => c.coordination?.consensusStrategy !== undefined,
|
|
63
64
|
pattern: 'consensus',
|
|
64
65
|
},
|
|
66
|
+
|
|
67
|
+
// ── Specific role-based patterns (check before generic hub patterns) ──
|
|
65
68
|
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
// Map-reduce: requires BOTH mapper AND reducer roles
|
|
70
|
+
test: (c) => c.agents.some((a) => a.role === 'mapper') && c.agents.some((a) => a.role === 'reducer'),
|
|
71
|
+
pattern: 'map-reduce',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
// Red-team: requires BOTH attacker/red-team AND defender/blue-team
|
|
75
|
+
test: (c) => c.agents.some((a) => a.role === 'attacker' || a.role === 'red-team') &&
|
|
76
|
+
c.agents.some((a) => a.role === 'defender' || a.role === 'blue-team'),
|
|
77
|
+
pattern: 'red-team',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
// Reflection: requires critic role (not just reviewer, which is too common)
|
|
81
|
+
test: (c) => c.agents.some((a) => a.role === 'critic'),
|
|
82
|
+
pattern: 'reflection',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
// Escalation: has tier-N roles
|
|
86
|
+
test: (c) => c.agents.some((a) => a.role?.startsWith('tier-')),
|
|
87
|
+
pattern: 'escalation',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
// Auction: has auctioneer role
|
|
91
|
+
test: (c) => c.agents.some((a) => a.role === 'auctioneer'),
|
|
92
|
+
pattern: 'auction',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
// Saga: has saga-orchestrator or compensate-handler roles
|
|
96
|
+
test: (c) => c.agents.some((a) => a.role === 'saga-orchestrator' || a.role === 'compensate-handler'),
|
|
97
|
+
pattern: 'saga',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
// Circuit-breaker: has fallback or backup roles
|
|
101
|
+
test: (c) => c.agents.some((a) => a.role === 'fallback' || a.role === 'backup' || a.role === 'primary'),
|
|
102
|
+
pattern: 'circuit-breaker',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
// Blackboard: has blackboard or shared-workspace role
|
|
106
|
+
test: (c) => c.agents.some((a) => a.role === 'blackboard' || a.role === 'shared-workspace'),
|
|
107
|
+
pattern: 'blackboard',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
// Swarm: has hive-mind or swarm-agent roles
|
|
111
|
+
test: (c) => c.agents.some((a) => a.role === 'hive-mind' || a.role === 'swarm-agent'),
|
|
112
|
+
pattern: 'swarm',
|
|
73
113
|
},
|
|
114
|
+
{
|
|
115
|
+
// Verifier: has verifier role
|
|
116
|
+
test: (c) => c.agents.some((a) => a.role === 'verifier'),
|
|
117
|
+
pattern: 'verifier',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
// Supervisor: has supervisor role
|
|
121
|
+
test: (c) => c.agents.some((a) => a.role === 'supervisor'),
|
|
122
|
+
pattern: 'supervisor',
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
// ── Generic hub-based patterns ────────────────────────────────────────
|
|
74
126
|
{
|
|
75
127
|
test: (c) => c.agents.length > 3 && c.agents.some((a) => a.role === 'lead'),
|
|
76
128
|
pattern: 'hierarchical',
|
|
@@ -79,8 +131,20 @@ const PATTERN_HEURISTICS: Array<{
|
|
|
79
131
|
test: (c) => c.agents.some((a) => a.role === 'hub' || a.role === 'coordinator'),
|
|
80
132
|
pattern: 'hub-spoke',
|
|
81
133
|
},
|
|
134
|
+
|
|
135
|
+
// ── Structural patterns ───────────────────────────────────────────────
|
|
136
|
+
{
|
|
137
|
+
test: (c) =>
|
|
138
|
+
Array.isArray(c.workflows) &&
|
|
139
|
+
c.workflows.some((w) => {
|
|
140
|
+
const names = w.steps.map((s) => s.agent);
|
|
141
|
+
return new Set(names).size === names.length && names.length > 2;
|
|
142
|
+
}),
|
|
143
|
+
pattern: 'pipeline',
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// ── Default fallback ──────────────────────────────────────────────────
|
|
82
147
|
{
|
|
83
|
-
// Default: many independent agents → fan-out
|
|
84
148
|
test: () => true,
|
|
85
149
|
pattern: 'fan-out',
|
|
86
150
|
},
|
|
@@ -207,6 +271,164 @@ export class SwarmCoordinator extends EventEmitter {
|
|
|
207
271
|
return { pattern: p, agents, edges, hub };
|
|
208
272
|
}
|
|
209
273
|
|
|
274
|
+
// ── Additional patterns ────────────────────────────────────────────
|
|
275
|
+
|
|
276
|
+
case 'map-reduce': {
|
|
277
|
+
// Mappers fan out from coordinator, all feed into reducer(s)
|
|
278
|
+
const coordinator = this.pickHub(agents);
|
|
279
|
+
const mappers = agents.filter((a) => a.role === 'mapper').map((a) => a.name);
|
|
280
|
+
const reducers = agents.filter((a) => a.role === 'reducer').map((a) => a.name);
|
|
281
|
+
const others = names.filter((n) => n !== coordinator && !mappers.includes(n) && !reducers.includes(n));
|
|
282
|
+
|
|
283
|
+
// Coordinator → mappers (excluding self if coordinator is also a mapper)
|
|
284
|
+
edges.set(coordinator, [...mappers.filter((m) => m !== coordinator), ...others]);
|
|
285
|
+
// Mappers → reducers (skip coordinator to avoid overwriting its edges)
|
|
286
|
+
for (const m of mappers) {
|
|
287
|
+
if (m === coordinator) continue;
|
|
288
|
+
edges.set(m, reducers.length > 0 ? reducers : [coordinator]);
|
|
289
|
+
}
|
|
290
|
+
// Reducers → coordinator
|
|
291
|
+
for (const r of reducers) edges.set(r, [coordinator]);
|
|
292
|
+
// Others → coordinator
|
|
293
|
+
for (const o of others) edges.set(o, [coordinator]);
|
|
294
|
+
|
|
295
|
+
return { pattern: p, agents, edges, hub: coordinator };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
case 'scatter-gather': {
|
|
299
|
+
// Hub scatters to all workers, gathers responses back
|
|
300
|
+
const hub = this.pickHub(agents);
|
|
301
|
+
const workers = names.filter((n) => n !== hub);
|
|
302
|
+
edges.set(hub, workers);
|
|
303
|
+
for (const w of workers) edges.set(w, [hub]);
|
|
304
|
+
return { pattern: p, agents, edges, hub };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
case 'supervisor': {
|
|
308
|
+
// Supervisor monitors all workers; workers report to supervisor
|
|
309
|
+
const supervisor = agents.find((a) => a.role === 'supervisor')?.name ?? this.pickHub(agents);
|
|
310
|
+
const workers = names.filter((n) => n !== supervisor);
|
|
311
|
+
edges.set(supervisor, workers);
|
|
312
|
+
for (const w of workers) edges.set(w, [supervisor]);
|
|
313
|
+
return { pattern: p, agents, edges, hub: supervisor };
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
case 'reflection': {
|
|
317
|
+
// Agent produces output, critic reviews and sends feedback
|
|
318
|
+
// Linear: producer → critic → producer (loop-capable)
|
|
319
|
+
const critic = agents.find((a) => a.role === 'critic' || a.role === 'reviewer')?.name;
|
|
320
|
+
const producers = names.filter((n) => n !== critic);
|
|
321
|
+
if (critic) {
|
|
322
|
+
for (const prod of producers) {
|
|
323
|
+
edges.set(prod, [critic]);
|
|
324
|
+
}
|
|
325
|
+
edges.set(critic, producers);
|
|
326
|
+
} else {
|
|
327
|
+
// Fallback: self-reflection via mesh
|
|
328
|
+
for (const n of names) edges.set(n, names.filter((o) => o !== n));
|
|
329
|
+
}
|
|
330
|
+
return { pattern: p, agents, edges };
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
case 'red-team': {
|
|
334
|
+
// Attacker ↔ Defender adversarial communication
|
|
335
|
+
const attackers = agents.filter((a) => a.role === 'attacker' || a.role === 'red-team').map((a) => a.name);
|
|
336
|
+
const defenders = agents.filter((a) => a.role === 'defender' || a.role === 'blue-team').map((a) => a.name);
|
|
337
|
+
const judges = names.filter((n) => !attackers.includes(n) && !defenders.includes(n));
|
|
338
|
+
|
|
339
|
+
// Attackers → defenders and judges
|
|
340
|
+
for (const a of attackers) edges.set(a, [...defenders, ...judges]);
|
|
341
|
+
// Defenders → attackers and judges
|
|
342
|
+
for (const d of defenders) edges.set(d, [...attackers, ...judges]);
|
|
343
|
+
// Judges receive from both, can communicate with all
|
|
344
|
+
for (const j of judges) edges.set(j, [...attackers, ...defenders]);
|
|
345
|
+
|
|
346
|
+
return { pattern: p, agents, edges };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
case 'verifier': {
|
|
350
|
+
// Producer → Verifier chain; verifier can reject back to producer
|
|
351
|
+
const verifiers = agents.filter((a) => a.role === 'verifier').map((a) => a.name);
|
|
352
|
+
const producers = names.filter((n) => !verifiers.includes(n));
|
|
353
|
+
|
|
354
|
+
for (const prod of producers) edges.set(prod, verifiers.length > 0 ? verifiers : []);
|
|
355
|
+
for (const v of verifiers) edges.set(v, producers); // Can send rejections back
|
|
356
|
+
|
|
357
|
+
return { pattern: p, agents, edges };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
case 'auction': {
|
|
361
|
+
// Auctioneer broadcasts tasks; bidders respond to auctioneer only
|
|
362
|
+
const auctioneer = agents.find((a) => a.role === 'auctioneer')?.name ?? this.pickHub(agents);
|
|
363
|
+
const bidders = names.filter((n) => n !== auctioneer);
|
|
364
|
+
edges.set(auctioneer, bidders);
|
|
365
|
+
for (const b of bidders) edges.set(b, [auctioneer]);
|
|
366
|
+
return { pattern: p, agents, edges, hub: auctioneer };
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
case 'escalation': {
|
|
370
|
+
// Tiered chain: each level can escalate to the next
|
|
371
|
+
// Uses agent order or tier role numbers
|
|
372
|
+
const order = this.resolveEscalationOrder(agents);
|
|
373
|
+
for (let i = 0; i < order.length; i++) {
|
|
374
|
+
// Each tier can escalate up and report down
|
|
375
|
+
const canEscalateTo = i < order.length - 1 ? [order[i + 1]] : [];
|
|
376
|
+
const canReportTo = i > 0 ? [order[i - 1]] : [];
|
|
377
|
+
edges.set(order[i], [...canEscalateTo, ...canReportTo]);
|
|
378
|
+
}
|
|
379
|
+
// Ensure non-tiered agents still have edge entries (prevents undefined)
|
|
380
|
+
for (const n of names) {
|
|
381
|
+
if (!edges.has(n)) edges.set(n, []);
|
|
382
|
+
}
|
|
383
|
+
return { pattern: p, agents, edges, pipelineOrder: order };
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
case 'saga': {
|
|
387
|
+
// Orchestrator coordinates saga steps; each step can trigger compensate
|
|
388
|
+
const orchestrator = agents.find((a) => a.role === 'saga-orchestrator')?.name ?? this.pickHub(agents);
|
|
389
|
+
const participants = names.filter((n) => n !== orchestrator);
|
|
390
|
+
// Orchestrator → all participants (for commands)
|
|
391
|
+
edges.set(orchestrator, participants);
|
|
392
|
+
// Participants → orchestrator (for completion/failure signals)
|
|
393
|
+
for (const part of participants) edges.set(part, [orchestrator]);
|
|
394
|
+
return { pattern: p, agents, edges, hub: orchestrator };
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
case 'circuit-breaker': {
|
|
398
|
+
// Primary agent with fallback chain
|
|
399
|
+
const order = names; // First agent is primary, rest are fallbacks
|
|
400
|
+
for (let i = 0; i < order.length; i++) {
|
|
401
|
+
// Each can trigger next fallback
|
|
402
|
+
edges.set(order[i], i < order.length - 1 ? [order[i + 1]] : []);
|
|
403
|
+
}
|
|
404
|
+
return { pattern: p, agents, edges, pipelineOrder: order };
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
case 'blackboard': {
|
|
408
|
+
// All agents can read/write to shared blackboard (full mesh)
|
|
409
|
+
// Plus optional moderator
|
|
410
|
+
const moderator = agents.find((a) => a.role === 'moderator')?.name;
|
|
411
|
+
for (const n of names) {
|
|
412
|
+
edges.set(n, names.filter((o) => o !== n));
|
|
413
|
+
}
|
|
414
|
+
return { pattern: p, agents, edges, hub: moderator };
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
case 'swarm': {
|
|
418
|
+
// Emergent swarm: agents communicate with nearest neighbors
|
|
419
|
+
// For simplicity, partial mesh based on agent index proximity
|
|
420
|
+
const hiveMind = agents.find((a) => a.role === 'hive-mind')?.name;
|
|
421
|
+
for (let i = 0; i < names.length; i++) {
|
|
422
|
+
const neighbors: string[] = [];
|
|
423
|
+
if (i > 0) neighbors.push(names[i - 1]);
|
|
424
|
+
if (i < names.length - 1) neighbors.push(names[i + 1]);
|
|
425
|
+
// Also connect to hive mind if present (avoid duplicates if already adjacent)
|
|
426
|
+
if (hiveMind && hiveMind !== names[i] && !neighbors.includes(hiveMind)) neighbors.push(hiveMind);
|
|
427
|
+
edges.set(names[i], neighbors);
|
|
428
|
+
}
|
|
429
|
+
return { pattern: p, agents, edges, hub: hiveMind };
|
|
430
|
+
}
|
|
431
|
+
|
|
210
432
|
default: {
|
|
211
433
|
// Fallback: full mesh.
|
|
212
434
|
for (const n of names) {
|
|
@@ -490,6 +712,22 @@ export class SwarmCoordinator extends EventEmitter {
|
|
|
490
712
|
return order.length > 0 ? order : fallback;
|
|
491
713
|
}
|
|
492
714
|
|
|
715
|
+
private resolveEscalationOrder(agents: AgentDefinition[]): string[] {
|
|
716
|
+
// Sort by tier role (e.g., "tier-1", "tier-2") or by agent order
|
|
717
|
+
const tiered = agents.filter((a) => a.role?.startsWith('tier-'));
|
|
718
|
+
if (tiered.length > 0) {
|
|
719
|
+
return tiered
|
|
720
|
+
.sort((a, b) => {
|
|
721
|
+
const tierA = parseInt(a.role?.replace('tier-', '') ?? '0', 10);
|
|
722
|
+
const tierB = parseInt(b.role?.replace('tier-', '') ?? '0', 10);
|
|
723
|
+
return tierA - tierB;
|
|
724
|
+
})
|
|
725
|
+
.map((a) => a.name);
|
|
726
|
+
}
|
|
727
|
+
// Fallback: use agent order
|
|
728
|
+
return agents.map((a) => a.name);
|
|
729
|
+
}
|
|
730
|
+
|
|
493
731
|
private resolveDAGEdges(config: RelayYamlConfig): Map<string, string[]> {
|
|
494
732
|
const edges = new Map<string, string[]>();
|
|
495
733
|
const workflows = config.workflows ?? [];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentRelayOptions } from '../relay.js';
|
|
2
|
-
import type { WorkflowRunRow } from './types.js';
|
|
2
|
+
import type { TrajectoryConfig, WorkflowRunRow } from './types.js';
|
|
3
3
|
import { WorkflowRunner, type WorkflowEventListener, type VariableContext } from './runner.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -16,6 +16,8 @@ export interface RunWorkflowOptions {
|
|
|
16
16
|
relay?: AgentRelayOptions;
|
|
17
17
|
/** Progress callback for workflow events. */
|
|
18
18
|
onEvent?: WorkflowEventListener;
|
|
19
|
+
/** Override trajectory config. Set to false to disable trajectory recording. */
|
|
20
|
+
trajectories?: TrajectoryConfig | false;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
/**
|
|
@@ -43,5 +45,11 @@ export async function runWorkflow(
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
const config = await runner.parseYamlFile(yamlPath);
|
|
48
|
+
|
|
49
|
+
// Allow programmatic trajectory override
|
|
50
|
+
if (options.trajectories !== undefined) {
|
|
51
|
+
config.trajectories = options.trajectories;
|
|
52
|
+
}
|
|
53
|
+
|
|
46
54
|
return runner.execute(config, options.workflow, options.vars);
|
|
47
55
|
}
|