@cogitator-ai/swarms 0.4.19 → 0.5.1
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 +245 -897
- package/dist/agents.d.ts +13 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +70 -0
- package/dist/agents.js.map +1 -0
- package/dist/assessor/assessor.d.ts +9 -2
- package/dist/assessor/assessor.d.ts.map +1 -1
- package/dist/assessor/assessor.js +89 -61
- package/dist/assessor/assessor.js.map +1 -1
- package/dist/assessor/role-matcher.d.ts +6 -24
- package/dist/assessor/role-matcher.d.ts.map +1 -1
- package/dist/assessor/role-matcher.js +9 -37
- package/dist/assessor/role-matcher.js.map +1 -1
- package/dist/assessor/scoring.js +1 -1
- package/dist/assessor/scoring.js.map +1 -1
- package/dist/assessor/task-analyzer.d.ts.map +1 -1
- package/dist/assessor/task-analyzer.js +4 -19
- package/dist/assessor/task-analyzer.js.map +1 -1
- package/dist/base-coordinator.d.ts +117 -0
- package/dist/base-coordinator.d.ts.map +1 -0
- package/dist/base-coordinator.js +455 -0
- package/dist/base-coordinator.js.map +1 -0
- package/dist/communication/blackboard.d.ts +34 -4
- package/dist/communication/blackboard.d.ts.map +1 -1
- package/dist/communication/blackboard.js +80 -41
- package/dist/communication/blackboard.js.map +1 -1
- package/dist/communication/event-emitter.d.ts +1 -1
- package/dist/communication/event-emitter.d.ts.map +1 -1
- package/dist/communication/event-emitter.js +6 -17
- package/dist/communication/event-emitter.js.map +1 -1
- package/dist/communication/index.d.ts +2 -2
- package/dist/communication/index.d.ts.map +1 -1
- package/dist/communication/index.js +2 -2
- package/dist/communication/index.js.map +1 -1
- package/dist/communication/message-bus.d.ts +48 -5
- package/dist/communication/message-bus.d.ts.map +1 -1
- package/dist/communication/message-bus.js +135 -50
- package/dist/communication/message-bus.js.map +1 -1
- package/dist/communication/redis-blackboard.d.ts +12 -5
- package/dist/communication/redis-blackboard.d.ts.map +1 -1
- package/dist/communication/redis-blackboard.js +214 -94
- package/dist/communication/redis-blackboard.js.map +1 -1
- package/dist/communication/redis-event-emitter.d.ts +14 -1
- package/dist/communication/redis-event-emitter.d.ts.map +1 -1
- package/dist/communication/redis-event-emitter.js +107 -47
- package/dist/communication/redis-event-emitter.js.map +1 -1
- package/dist/communication/redis-message-bus.d.ts +13 -6
- package/dist/communication/redis-message-bus.d.ts.map +1 -1
- package/dist/communication/redis-message-bus.js +93 -66
- package/dist/communication/redis-message-bus.js.map +1 -1
- package/dist/coordinator.d.ts +7 -41
- package/dist/coordinator.d.ts.map +1 -1
- package/dist/coordinator.js +17 -336
- package/dist/coordinator.js.map +1 -1
- package/dist/distributed/distributed-coordinator.d.ts +55 -49
- package/dist/distributed/distributed-coordinator.d.ts.map +1 -1
- package/dist/distributed/distributed-coordinator.js +166 -253
- package/dist/distributed/distributed-coordinator.js.map +1 -1
- package/dist/distributed/index.d.ts +1 -1
- package/dist/distributed/index.d.ts.map +1 -1
- package/dist/distributed/index.js +1 -1
- package/dist/distributed/index.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/resources/circuit-breaker.d.ts +1 -6
- package/dist/resources/circuit-breaker.d.ts.map +1 -1
- package/dist/resources/circuit-breaker.js +14 -17
- package/dist/resources/circuit-breaker.js.map +1 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js.map +1 -1
- package/dist/resources/tracker.d.ts.map +1 -1
- package/dist/resources/tracker.js +8 -5
- package/dist/resources/tracker.js.map +1 -1
- package/dist/shared/hierarchy.d.ts +21 -0
- package/dist/shared/hierarchy.d.ts.map +1 -0
- package/dist/shared/hierarchy.js +27 -0
- package/dist/shared/hierarchy.js.map +1 -0
- package/dist/shared/negotiation.d.ts +27 -0
- package/dist/shared/negotiation.d.ts.map +1 -0
- package/dist/shared/negotiation.js +55 -0
- package/dist/shared/negotiation.js.map +1 -0
- package/dist/shared/voting.d.ts +6 -0
- package/dist/shared/voting.d.ts.map +1 -0
- package/dist/shared/voting.js +13 -0
- package/dist/shared/voting.js.map +1 -0
- package/dist/strategies/auction.js +2 -3
- package/dist/strategies/auction.js.map +1 -1
- package/dist/strategies/consensus.d.ts +12 -0
- package/dist/strategies/consensus.d.ts.map +1 -1
- package/dist/strategies/consensus.js +81 -40
- package/dist/strategies/consensus.js.map +1 -1
- package/dist/strategies/debate.d.ts.map +1 -1
- package/dist/strategies/debate.js +19 -9
- package/dist/strategies/debate.js.map +1 -1
- package/dist/strategies/hierarchical.d.ts.map +1 -1
- package/dist/strategies/hierarchical.js +29 -12
- package/dist/strategies/hierarchical.js.map +1 -1
- package/dist/strategies/index.d.ts +8 -7
- package/dist/strategies/index.d.ts.map +1 -1
- package/dist/strategies/index.js +1 -7
- package/dist/strategies/index.js.map +1 -1
- package/dist/strategies/negotiation/approval.d.ts.map +1 -1
- package/dist/strategies/negotiation/approval.js +47 -21
- package/dist/strategies/negotiation/approval.js.map +1 -1
- package/dist/strategies/negotiation/convergence.js +1 -1
- package/dist/strategies/negotiation-strategy.d.ts +24 -2
- package/dist/strategies/negotiation-strategy.d.ts.map +1 -1
- package/dist/strategies/negotiation-strategy.js +281 -158
- package/dist/strategies/negotiation-strategy.js.map +1 -1
- package/dist/strategies/pipeline.d.ts.map +1 -1
- package/dist/strategies/pipeline.js +19 -11
- package/dist/strategies/pipeline.js.map +1 -1
- package/dist/swarm.d.ts +24 -15
- package/dist/swarm.d.ts.map +1 -1
- package/dist/swarm.js +193 -116
- package/dist/swarm.js.map +1 -1
- package/dist/tools/blackboard.d.ts +1 -1
- package/dist/tools/blackboard.d.ts.map +1 -1
- package/dist/tools/blackboard.js +26 -6
- package/dist/tools/blackboard.js.map +1 -1
- package/dist/tools/delegation.d.ts +23 -4
- package/dist/tools/delegation.d.ts.map +1 -1
- package/dist/tools/delegation.js +116 -85
- package/dist/tools/delegation.js.map +1 -1
- package/dist/tools/index.d.ts +3 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +19 -4
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/messaging.d.ts +36 -7
- package/dist/tools/messaging.d.ts.map +1 -1
- package/dist/tools/messaging.js +122 -46
- package/dist/tools/messaging.js.map +1 -1
- package/dist/tools/negotiation.d.ts +8 -4
- package/dist/tools/negotiation.d.ts.map +1 -1
- package/dist/tools/negotiation.js +135 -85
- package/dist/tools/negotiation.js.map +1 -1
- package/dist/tools/voting.d.ts +3 -0
- package/dist/tools/voting.d.ts.map +1 -1
- package/dist/tools/voting.js +13 -12
- package/dist/tools/voting.js.map +1 -1
- package/dist/utils/concurrency.d.ts +10 -0
- package/dist/utils/concurrency.d.ts.map +1 -0
- package/dist/utils/concurrency.js +28 -0
- package/dist/utils/concurrency.js.map +1 -0
- package/dist/utils/invoke.d.ts +2 -0
- package/dist/utils/invoke.d.ts.map +1 -0
- package/dist/utils/invoke.js +19 -0
- package/dist/utils/invoke.js.map +1 -0
- package/dist/workflow/swarm-node.d.ts.map +1 -1
- package/dist/workflow/swarm-node.js +56 -71
- package/dist/workflow/swarm-node.js.map +1 -1
- package/package.json +6 -6
|
@@ -7,10 +7,6 @@ const VISION_KEYWORDS = [
|
|
|
7
7
|
'chart',
|
|
8
8
|
'graph',
|
|
9
9
|
'visual',
|
|
10
|
-
'see',
|
|
11
|
-
'look at',
|
|
12
|
-
'analyze this',
|
|
13
|
-
'show me',
|
|
14
10
|
'drawing',
|
|
15
11
|
'illustration',
|
|
16
12
|
'png',
|
|
@@ -23,17 +19,12 @@ const TOOL_KEYWORDS = [
|
|
|
23
19
|
'search',
|
|
24
20
|
'calculate',
|
|
25
21
|
'execute',
|
|
26
|
-
'run',
|
|
27
22
|
'fetch',
|
|
28
23
|
'api',
|
|
29
24
|
'database',
|
|
30
|
-
'file',
|
|
31
|
-
'code',
|
|
32
25
|
'browse',
|
|
33
26
|
'query',
|
|
34
|
-
'call',
|
|
35
27
|
'invoke',
|
|
36
|
-
'request',
|
|
37
28
|
'download',
|
|
38
29
|
'upload',
|
|
39
30
|
'scrape',
|
|
@@ -96,10 +87,10 @@ export class TaskAnalyzer {
|
|
|
96
87
|
};
|
|
97
88
|
}
|
|
98
89
|
detectVision(task) {
|
|
99
|
-
return VISION_KEYWORDS.some((k) =>
|
|
90
|
+
return VISION_KEYWORDS.some((k) => new RegExp(`\\b${k}\\b`, 'i').test(task));
|
|
100
91
|
}
|
|
101
92
|
detectToolNeeds(task) {
|
|
102
|
-
return TOOL_KEYWORDS.some((k) =>
|
|
93
|
+
return TOOL_KEYWORDS.some((k) => new RegExp(`\\b${k}\\b`, 'i').test(task));
|
|
103
94
|
}
|
|
104
95
|
detectLongContext(task) {
|
|
105
96
|
const wordCount = task.split(/\s+/).length;
|
|
@@ -107,14 +98,9 @@ export class TaskAnalyzer {
|
|
|
107
98
|
return true;
|
|
108
99
|
const longContextIndicators = [
|
|
109
100
|
'document',
|
|
110
|
-
'file',
|
|
111
101
|
'codebase',
|
|
112
102
|
'repository',
|
|
113
|
-
'large',
|
|
114
103
|
'entire',
|
|
115
|
-
'full',
|
|
116
|
-
'complete',
|
|
117
|
-
'all of',
|
|
118
104
|
'whole',
|
|
119
105
|
'multiple files',
|
|
120
106
|
'many pages',
|
|
@@ -141,11 +127,10 @@ export class TaskAnalyzer {
|
|
|
141
127
|
return 'balanced';
|
|
142
128
|
}
|
|
143
129
|
detectCostSensitivity(task) {
|
|
144
|
-
|
|
145
|
-
if (/\b(cheap|free|budget|low.?cost|economical)\b/.test(lower)) {
|
|
130
|
+
if (/\b(cheap|free|budget|low.?cost|economical)\b/.test(task)) {
|
|
146
131
|
return 'high';
|
|
147
132
|
}
|
|
148
|
-
if (/\b(best|premium|quality|accurate|precise)\b/.test(
|
|
133
|
+
if (/\b(best|premium|quality|accurate|precise)\b/.test(task)) {
|
|
149
134
|
return 'low';
|
|
150
135
|
}
|
|
151
136
|
return 'medium';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-analyzer.js","sourceRoot":"","sources":["../../src/assessor/task-analyzer.ts"],"names":[],"mappings":"AAQA,MAAM,eAAe,GAAG;IACtB,OAAO;IACP,OAAO;IACP,SAAS;IACT,YAAY;IACZ,SAAS;IACT,OAAO;IACP,OAAO;IACP,QAAQ;IACR,
|
|
1
|
+
{"version":3,"file":"task-analyzer.js","sourceRoot":"","sources":["../../src/assessor/task-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { Agent, SwarmConfig, SwarmAgent, SwarmAgentMetadata, SwarmAgentRunOptions, SwarmResourceUsage, RunResult, SwarmEventEmitter, SwarmCoordinatorInterface, Tool } from '@cogitator-ai/types';
|
|
2
|
+
import type { ReadTrackingMessageBus } from './communication/message-bus.js';
|
|
3
|
+
import type { ObservableBlackboard } from './communication/blackboard.js';
|
|
4
|
+
import { ResourceTracker } from './resources/tracker.js';
|
|
5
|
+
type RetryConfig = NonNullable<NonNullable<SwarmConfig['errorHandling']>['retry']>;
|
|
6
|
+
export interface SwarmRunScope {
|
|
7
|
+
/** Base thread id; each agent gets its own `${threadId}:${agentName}` thread */
|
|
8
|
+
threadId?: string;
|
|
9
|
+
/** Signal that cancels every agent run of the current swarm run */
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
}
|
|
12
|
+
export interface SwarmCommunication<Bus extends ReadTrackingMessageBus = ReadTrackingMessageBus, Board extends ObservableBlackboard = ObservableBlackboard, Events extends SwarmEventEmitter = SwarmEventEmitter> {
|
|
13
|
+
messageBus: Bus;
|
|
14
|
+
blackboard: Board;
|
|
15
|
+
events: Events;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Everything an execution engine needs to run one agent turn.
|
|
19
|
+
*/
|
|
20
|
+
export interface AgentRunRequest {
|
|
21
|
+
swarmAgent: SwarmAgent;
|
|
22
|
+
/** Agent to execute, with `resources.perAgent` limits applied */
|
|
23
|
+
agent: Agent;
|
|
24
|
+
input: string;
|
|
25
|
+
/** Full run context including swarm, message and negotiation context */
|
|
26
|
+
context: Record<string, unknown>;
|
|
27
|
+
signal: AbortSignal;
|
|
28
|
+
threadId?: string;
|
|
29
|
+
timeout?: number;
|
|
30
|
+
saveHistory: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Shared coordination logic for local and distributed swarms: agent registry, budgets,
|
|
34
|
+
* circuit breaking, error recovery, pause/abort, parallel scheduling and observability.
|
|
35
|
+
* Subclasses only decide how a single agent turn is executed.
|
|
36
|
+
*/
|
|
37
|
+
export declare abstract class BaseSwarmCoordinator<Bus extends ReadTrackingMessageBus = ReadTrackingMessageBus, Board extends ObservableBlackboard = ObservableBlackboard, Events extends SwarmEventEmitter = SwarmEventEmitter> implements SwarmCoordinatorInterface {
|
|
38
|
+
protected readonly config: SwarmConfig;
|
|
39
|
+
protected readonly swarmId: string;
|
|
40
|
+
protected readonly agents: Map<string, SwarmAgent>;
|
|
41
|
+
protected readonly communication: SwarmCommunication<Bus, Board, Events>;
|
|
42
|
+
protected resourceTracker: ResourceTracker;
|
|
43
|
+
protected saveHistory: boolean;
|
|
44
|
+
private circuitBreaker?;
|
|
45
|
+
private limitedAgents;
|
|
46
|
+
private injectedTools;
|
|
47
|
+
private abortController;
|
|
48
|
+
private runScope;
|
|
49
|
+
private paused;
|
|
50
|
+
protected constructor(config: SwarmConfig, swarmId: string, communication: SwarmCommunication<Bus, Board, Events>);
|
|
51
|
+
/**
|
|
52
|
+
* Execute a single agent turn. Implementations must honour `request.signal`.
|
|
53
|
+
*/
|
|
54
|
+
protected abstract executeRun(request: AgentRunRequest): Promise<RunResult>;
|
|
55
|
+
/**
|
|
56
|
+
* Hook for engines that need asynchronous setup before the first agent run.
|
|
57
|
+
*/
|
|
58
|
+
protected prepare(): Promise<void>;
|
|
59
|
+
get messageBus(): Bus;
|
|
60
|
+
get blackboard(): Board;
|
|
61
|
+
get events(): Events;
|
|
62
|
+
setSaveHistory(value: boolean): void;
|
|
63
|
+
getSwarmId(): string;
|
|
64
|
+
getAgent(name: string): SwarmAgent | undefined;
|
|
65
|
+
getAgents(): SwarmAgent[];
|
|
66
|
+
getAgentsByRole(role: SwarmAgentMetadata['role']): SwarmAgent[];
|
|
67
|
+
getResourceUsage(): SwarmResourceUsage;
|
|
68
|
+
/**
|
|
69
|
+
* Start a new swarm run: resource budgets are per run, so usage counters restart here.
|
|
70
|
+
*/
|
|
71
|
+
beginRun(scope?: SwarmRunScope): void;
|
|
72
|
+
endRun(): void;
|
|
73
|
+
pause(): void;
|
|
74
|
+
resume(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Abort the swarm: pending agent runs are rejected and in-flight runs are cancelled.
|
|
77
|
+
*/
|
|
78
|
+
abort(): void;
|
|
79
|
+
isAborted(): boolean;
|
|
80
|
+
isPaused(): boolean;
|
|
81
|
+
reset(): void;
|
|
82
|
+
runAgent(agentName: string, input: string, context?: Record<string, unknown>, options?: SwarmAgentRunOptions): Promise<RunResult>;
|
|
83
|
+
runAgentsParallel(agents: {
|
|
84
|
+
name: string;
|
|
85
|
+
input: string;
|
|
86
|
+
context?: Record<string, unknown>;
|
|
87
|
+
}[], maxConcurrency?: number): Promise<Map<string, RunResult>>;
|
|
88
|
+
private runAgentWithRecovery;
|
|
89
|
+
private requireAgent;
|
|
90
|
+
private ensureRunnable;
|
|
91
|
+
protected isCancelled(): boolean;
|
|
92
|
+
private currentSignal;
|
|
93
|
+
private executeAgent;
|
|
94
|
+
/**
|
|
95
|
+
* Tools a strategy needs an agent to have: the supervisor of a hierarchical swarm gets the
|
|
96
|
+
* delegation tools, negotiating agents get the negotiation tools. Tools the agent already
|
|
97
|
+
* defines (by name) are left untouched. Engines that cannot ship tool implementations
|
|
98
|
+
* (e.g. remote workers) override this.
|
|
99
|
+
*/
|
|
100
|
+
protected strategyTools(swarmAgent: SwarmAgent): Tool[];
|
|
101
|
+
private missingStrategyTools;
|
|
102
|
+
/**
|
|
103
|
+
* The agent actually executed for a turn: a cached clone when strategy tools,
|
|
104
|
+
* `resources.perAgent` limits or per-turn token caps apply, otherwise the agent itself.
|
|
105
|
+
*/
|
|
106
|
+
private getRunnableAgent;
|
|
107
|
+
private handleAgentError;
|
|
108
|
+
private retryAgentRun;
|
|
109
|
+
private setAgentState;
|
|
110
|
+
private wireObservability;
|
|
111
|
+
private collectIncomingMessages;
|
|
112
|
+
private buildNegotiationContext;
|
|
113
|
+
}
|
|
114
|
+
export declare function computeBackoffDelay(backoff: RetryConfig['backoff'], attempt: number, initialDelay: number, maxDelay: number): number;
|
|
115
|
+
export declare function toError(error: unknown): Error;
|
|
116
|
+
export {};
|
|
117
|
+
//# sourceMappingURL=base-coordinator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-coordinator.d.ts","sourceRoot":"","sources":["../src/base-coordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
import { getLogger } from '@cogitator-ai/core';
|
|
3
|
+
import { ResourceTracker } from './resources/tracker.js';
|
|
4
|
+
import { CircuitBreaker } from './resources/circuit-breaker.js';
|
|
5
|
+
import { buildSwarmAgents } from './agents.js';
|
|
6
|
+
import { runWithConcurrency } from './utils/concurrency.js';
|
|
7
|
+
import { createDelegationTools } from './tools/delegation.js';
|
|
8
|
+
import { createNegotiationTools } from './tools/negotiation.js';
|
|
9
|
+
/**
|
|
10
|
+
* Shared coordination logic for local and distributed swarms: agent registry, budgets,
|
|
11
|
+
* circuit breaking, error recovery, pause/abort, parallel scheduling and observability.
|
|
12
|
+
* Subclasses only decide how a single agent turn is executed.
|
|
13
|
+
*/
|
|
14
|
+
export class BaseSwarmCoordinator {
|
|
15
|
+
config;
|
|
16
|
+
swarmId;
|
|
17
|
+
agents;
|
|
18
|
+
communication;
|
|
19
|
+
resourceTracker;
|
|
20
|
+
saveHistory = true;
|
|
21
|
+
circuitBreaker;
|
|
22
|
+
limitedAgents = new Map();
|
|
23
|
+
injectedTools = new Map();
|
|
24
|
+
abortController = new AbortController();
|
|
25
|
+
runScope = {};
|
|
26
|
+
paused = false;
|
|
27
|
+
constructor(config, swarmId, communication) {
|
|
28
|
+
this.config = config;
|
|
29
|
+
this.swarmId = swarmId;
|
|
30
|
+
this.communication = communication;
|
|
31
|
+
this.agents = buildSwarmAgents(config);
|
|
32
|
+
this.resourceTracker = new ResourceTracker(config.resources ?? {});
|
|
33
|
+
if (config.errorHandling?.circuitBreaker?.enabled) {
|
|
34
|
+
this.circuitBreaker = new CircuitBreaker({
|
|
35
|
+
threshold: config.errorHandling.circuitBreaker.threshold,
|
|
36
|
+
resetTimeout: config.errorHandling.circuitBreaker.resetTimeout,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
this.wireObservability();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Hook for engines that need asynchronous setup before the first agent run.
|
|
43
|
+
*/
|
|
44
|
+
async prepare() { }
|
|
45
|
+
get messageBus() {
|
|
46
|
+
return this.communication.messageBus;
|
|
47
|
+
}
|
|
48
|
+
get blackboard() {
|
|
49
|
+
return this.communication.blackboard;
|
|
50
|
+
}
|
|
51
|
+
get events() {
|
|
52
|
+
return this.communication.events;
|
|
53
|
+
}
|
|
54
|
+
setSaveHistory(value) {
|
|
55
|
+
this.saveHistory = value;
|
|
56
|
+
}
|
|
57
|
+
getSwarmId() {
|
|
58
|
+
return this.swarmId;
|
|
59
|
+
}
|
|
60
|
+
getAgent(name) {
|
|
61
|
+
return this.agents.get(name);
|
|
62
|
+
}
|
|
63
|
+
getAgents() {
|
|
64
|
+
return Array.from(this.agents.values());
|
|
65
|
+
}
|
|
66
|
+
getAgentsByRole(role) {
|
|
67
|
+
return this.getAgents().filter((a) => a.metadata.role === role);
|
|
68
|
+
}
|
|
69
|
+
getResourceUsage() {
|
|
70
|
+
return this.resourceTracker.getUsage();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Start a new swarm run: resource budgets are per run, so usage counters restart here.
|
|
74
|
+
*/
|
|
75
|
+
beginRun(scope = {}) {
|
|
76
|
+
this.runScope = scope;
|
|
77
|
+
this.resourceTracker.reset();
|
|
78
|
+
}
|
|
79
|
+
endRun() {
|
|
80
|
+
this.runScope = {};
|
|
81
|
+
}
|
|
82
|
+
pause() {
|
|
83
|
+
this.paused = true;
|
|
84
|
+
}
|
|
85
|
+
resume() {
|
|
86
|
+
this.paused = false;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Abort the swarm: pending agent runs are rejected and in-flight runs are cancelled.
|
|
90
|
+
*/
|
|
91
|
+
abort() {
|
|
92
|
+
this.abortController.abort(new Error('Swarm execution aborted'));
|
|
93
|
+
}
|
|
94
|
+
isAborted() {
|
|
95
|
+
return this.abortController.signal.aborted;
|
|
96
|
+
}
|
|
97
|
+
isPaused() {
|
|
98
|
+
return this.paused;
|
|
99
|
+
}
|
|
100
|
+
reset() {
|
|
101
|
+
this.abortController = new AbortController();
|
|
102
|
+
this.paused = false;
|
|
103
|
+
this.runScope = {};
|
|
104
|
+
this.resourceTracker.reset();
|
|
105
|
+
this.circuitBreaker?.reset();
|
|
106
|
+
for (const agent of this.agents.values()) {
|
|
107
|
+
agent.state = 'idle';
|
|
108
|
+
agent.lastResult = undefined;
|
|
109
|
+
agent.messageCount = 0;
|
|
110
|
+
agent.tokenCount = 0;
|
|
111
|
+
}
|
|
112
|
+
this.messageBus.clear();
|
|
113
|
+
this.blackboard.clear();
|
|
114
|
+
}
|
|
115
|
+
async runAgent(agentName, input, context, options) {
|
|
116
|
+
return this.runAgentWithRecovery(agentName, input, context, options ?? {}, new Set());
|
|
117
|
+
}
|
|
118
|
+
async runAgentsParallel(agents, maxConcurrency) {
|
|
119
|
+
const concurrency = Math.max(1, maxConcurrency ?? this.config.resources?.maxConcurrency ?? 4);
|
|
120
|
+
const tolerateFailures = this.config.errorHandling?.onAgentFailure === 'skip' ||
|
|
121
|
+
this.config.errorHandling?.partialResults === true;
|
|
122
|
+
const outcomes = await runWithConcurrency(agents, concurrency, ({ name, input, context }) => this.runAgent(name, input, context), { stopOnFailure: !tolerateFailures });
|
|
123
|
+
const results = new Map();
|
|
124
|
+
let firstError;
|
|
125
|
+
let failures = 0;
|
|
126
|
+
outcomes.forEach((outcome, index) => {
|
|
127
|
+
if (!outcome)
|
|
128
|
+
return;
|
|
129
|
+
if (outcome.status === 'fulfilled') {
|
|
130
|
+
results.set(agents[index].name, outcome.value);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
failures++;
|
|
134
|
+
firstError ??= outcome.reason;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
if (failures > 0 && (!tolerateFailures || results.size === 0)) {
|
|
138
|
+
throw firstError;
|
|
139
|
+
}
|
|
140
|
+
return results;
|
|
141
|
+
}
|
|
142
|
+
async runAgentWithRecovery(agentName, input, context, options, failoverChain) {
|
|
143
|
+
const swarmAgent = this.requireAgent(agentName);
|
|
144
|
+
await this.ensureRunnable();
|
|
145
|
+
try {
|
|
146
|
+
return await this.executeAgent(swarmAgent, input, context, options);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (!this.config.errorHandling || this.isCancelled()) {
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
return this.handleAgentError(swarmAgent, input, context, options, toError(error), failoverChain);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
requireAgent(agentName) {
|
|
156
|
+
const swarmAgent = this.agents.get(agentName);
|
|
157
|
+
if (!swarmAgent) {
|
|
158
|
+
throw new Error(`Agent '${agentName}' not found in swarm`);
|
|
159
|
+
}
|
|
160
|
+
return swarmAgent;
|
|
161
|
+
}
|
|
162
|
+
async ensureRunnable() {
|
|
163
|
+
await this.prepare();
|
|
164
|
+
if (this.circuitBreaker && !this.circuitBreaker.canExecute()) {
|
|
165
|
+
throw new Error(`Circuit breaker is open for swarm '${this.config.name}'`);
|
|
166
|
+
}
|
|
167
|
+
if (!this.resourceTracker.isWithinBudget()) {
|
|
168
|
+
throw new Error('Swarm resource budget exceeded');
|
|
169
|
+
}
|
|
170
|
+
while (this.paused && !this.isCancelled()) {
|
|
171
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
172
|
+
}
|
|
173
|
+
if (this.isCancelled()) {
|
|
174
|
+
throw new Error('Swarm execution aborted');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
isCancelled() {
|
|
178
|
+
return this.abortController.signal.aborted || this.runScope.signal?.aborted === true;
|
|
179
|
+
}
|
|
180
|
+
currentSignal() {
|
|
181
|
+
const runSignal = this.runScope.signal;
|
|
182
|
+
return runSignal
|
|
183
|
+
? AbortSignal.any([this.abortController.signal, runSignal])
|
|
184
|
+
: this.abortController.signal;
|
|
185
|
+
}
|
|
186
|
+
async executeAgent(swarmAgent, input, context, options) {
|
|
187
|
+
const agentName = swarmAgent.agent.name;
|
|
188
|
+
this.setAgentState(agentName, 'running');
|
|
189
|
+
this.messageBus.resetTurnCounts(agentName);
|
|
190
|
+
this.events.emit('agent:start', { agentName, input }, agentName);
|
|
191
|
+
try {
|
|
192
|
+
const incomingMessages = this.collectIncomingMessages(agentName);
|
|
193
|
+
const negotiationContext = this.buildNegotiationContext(agentName);
|
|
194
|
+
const result = await this.executeRun({
|
|
195
|
+
swarmAgent,
|
|
196
|
+
agent: this.getRunnableAgent(swarmAgent, options.maxTokens),
|
|
197
|
+
input,
|
|
198
|
+
signal: this.currentSignal(),
|
|
199
|
+
saveHistory: this.saveHistory,
|
|
200
|
+
threadId: this.runScope.threadId ? `${this.runScope.threadId}:${agentName}` : undefined,
|
|
201
|
+
timeout: minDefined(this.config.resources?.perAgent?.timeout, options.timeout),
|
|
202
|
+
context: {
|
|
203
|
+
...context,
|
|
204
|
+
swarmContext: {
|
|
205
|
+
swarmId: this.swarmId,
|
|
206
|
+
swarmName: this.config.name,
|
|
207
|
+
agentRole: swarmAgent.metadata.role,
|
|
208
|
+
availableAgents: Array.from(this.agents.keys()).filter((n) => n !== agentName),
|
|
209
|
+
},
|
|
210
|
+
...(incomingMessages && { _incomingMessages: incomingMessages }),
|
|
211
|
+
...(negotiationContext && { _negotiation: negotiationContext }),
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
this.setAgentState(agentName, 'completed');
|
|
215
|
+
swarmAgent.lastResult = result;
|
|
216
|
+
swarmAgent.tokenCount += result.usage.totalTokens;
|
|
217
|
+
this.resourceTracker.trackAgentRun(agentName, result);
|
|
218
|
+
this.circuitBreaker?.recordSuccess();
|
|
219
|
+
this.events.emit('agent:complete', { agentName, result }, agentName);
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
this.setAgentState(agentName, 'failed');
|
|
224
|
+
this.circuitBreaker?.recordFailure();
|
|
225
|
+
this.events.emit('agent:error', { agentName, error }, agentName);
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Tools a strategy needs an agent to have: the supervisor of a hierarchical swarm gets the
|
|
231
|
+
* delegation tools, negotiating agents get the negotiation tools. Tools the agent already
|
|
232
|
+
* defines (by name) are left untouched. Engines that cannot ship tool implementations
|
|
233
|
+
* (e.g. remote workers) override this.
|
|
234
|
+
*/
|
|
235
|
+
strategyTools(swarmAgent) {
|
|
236
|
+
const name = swarmAgent.agent.name;
|
|
237
|
+
const role = swarmAgent.metadata.role;
|
|
238
|
+
switch (this.config.strategy) {
|
|
239
|
+
case 'hierarchical':
|
|
240
|
+
return role === 'supervisor'
|
|
241
|
+
? Object.values(createDelegationTools(this, this.blackboard, name))
|
|
242
|
+
: [];
|
|
243
|
+
case 'negotiation':
|
|
244
|
+
return role === 'supervisor' || role === 'moderator'
|
|
245
|
+
? []
|
|
246
|
+
: Object.values(createNegotiationTools(this.blackboard, this.events, name, swarmAgent.metadata.weight ?? this.config.negotiation?.weights?.[name] ?? 1));
|
|
247
|
+
default:
|
|
248
|
+
return [];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
missingStrategyTools(swarmAgent) {
|
|
252
|
+
let tools = this.injectedTools.get(swarmAgent.agent.name);
|
|
253
|
+
if (!tools) {
|
|
254
|
+
const existing = new Set(swarmAgent.agent.tools.map((t) => t.name));
|
|
255
|
+
tools = this.strategyTools(swarmAgent).filter((t) => !existing.has(t.name));
|
|
256
|
+
this.injectedTools.set(swarmAgent.agent.name, tools);
|
|
257
|
+
}
|
|
258
|
+
return tools;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* The agent actually executed for a turn: a cached clone when strategy tools,
|
|
262
|
+
* `resources.perAgent` limits or per-turn token caps apply, otherwise the agent itself.
|
|
263
|
+
*/
|
|
264
|
+
getRunnableAgent(swarmAgent, turnMaxTokens) {
|
|
265
|
+
const perAgent = this.config.resources?.perAgent;
|
|
266
|
+
const { maxIterations, maxTokens } = swarmAgent.agent.config;
|
|
267
|
+
const iterationLimit = minDefined(maxIterations, perAgent?.maxIterations);
|
|
268
|
+
const tokenLimit = minDefined(maxTokens, perAgent?.maxTokens, turnMaxTokens);
|
|
269
|
+
const extraTools = this.missingStrategyTools(swarmAgent);
|
|
270
|
+
const overrides = {};
|
|
271
|
+
if (iterationLimit !== maxIterations)
|
|
272
|
+
overrides.maxIterations = iterationLimit;
|
|
273
|
+
if (tokenLimit !== maxTokens)
|
|
274
|
+
overrides.maxTokens = tokenLimit;
|
|
275
|
+
if (extraTools.length > 0)
|
|
276
|
+
overrides.tools = [...swarmAgent.agent.tools, ...extraTools];
|
|
277
|
+
if (Object.keys(overrides).length === 0)
|
|
278
|
+
return swarmAgent.agent;
|
|
279
|
+
const cacheKey = `${swarmAgent.agent.name}|${iterationLimit ?? ''}|${tokenLimit ?? ''}`;
|
|
280
|
+
let runnable = this.limitedAgents.get(cacheKey);
|
|
281
|
+
if (!runnable) {
|
|
282
|
+
runnable = swarmAgent.agent.clone(overrides);
|
|
283
|
+
this.limitedAgents.set(cacheKey, runnable);
|
|
284
|
+
}
|
|
285
|
+
return runnable;
|
|
286
|
+
}
|
|
287
|
+
async handleAgentError(swarmAgent, input, context, options, error, failoverChain) {
|
|
288
|
+
const errorConfig = this.config.errorHandling;
|
|
289
|
+
const agentName = swarmAgent.agent.name;
|
|
290
|
+
switch (errorConfig.onAgentFailure) {
|
|
291
|
+
case 'retry':
|
|
292
|
+
if (errorConfig.retry && errorConfig.retry.maxRetries > 0) {
|
|
293
|
+
return this.retryAgentRun(swarmAgent, input, context, options, errorConfig.retry, error);
|
|
294
|
+
}
|
|
295
|
+
throw error;
|
|
296
|
+
case 'failover': {
|
|
297
|
+
failoverChain.add(agentName);
|
|
298
|
+
const backupAgentName = errorConfig.failover?.[agentName];
|
|
299
|
+
if (backupAgentName && !failoverChain.has(backupAgentName)) {
|
|
300
|
+
return this.runAgentWithRecovery(backupAgentName, input, context, options, failoverChain);
|
|
301
|
+
}
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
304
|
+
case 'skip':
|
|
305
|
+
return {
|
|
306
|
+
output: '',
|
|
307
|
+
runId: `run_skipped_${nanoid(8)}`,
|
|
308
|
+
agentId: swarmAgent.agent.id,
|
|
309
|
+
threadId: '',
|
|
310
|
+
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0, cost: 0, duration: 0 },
|
|
311
|
+
toolCalls: [],
|
|
312
|
+
messages: [],
|
|
313
|
+
trace: { traceId: `trace_${nanoid(12)}`, spans: [] },
|
|
314
|
+
};
|
|
315
|
+
case 'abort':
|
|
316
|
+
default:
|
|
317
|
+
throw error;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async retryAgentRun(swarmAgent, input, context, options, retryConfig, initialError) {
|
|
321
|
+
const { maxRetries, backoff, initialDelay = 1000, maxDelay = 30000 } = retryConfig;
|
|
322
|
+
let lastError = initialError;
|
|
323
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
324
|
+
await sleep(computeBackoffDelay(backoff, attempt, initialDelay, maxDelay));
|
|
325
|
+
await this.ensureRunnable();
|
|
326
|
+
try {
|
|
327
|
+
return await this.executeAgent(swarmAgent, input, context, options);
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
lastError = toError(error);
|
|
331
|
+
if (this.isCancelled())
|
|
332
|
+
throw lastError;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
throw new Error(`Agent '${swarmAgent.agent.name}' failed after ${maxRetries} retries: ${lastError.message}`, { cause: lastError });
|
|
336
|
+
}
|
|
337
|
+
setAgentState(agentName, state) {
|
|
338
|
+
const agent = this.agents.get(agentName);
|
|
339
|
+
if (agent) {
|
|
340
|
+
agent.state = state;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
wireObservability() {
|
|
344
|
+
const observability = this.config.observability;
|
|
345
|
+
const logger = getLogger();
|
|
346
|
+
this.messageBus.onMessage((message) => {
|
|
347
|
+
const sender = this.agents.get(message.from);
|
|
348
|
+
if (sender)
|
|
349
|
+
sender.messageCount++;
|
|
350
|
+
this.events.emit('message:sent', {
|
|
351
|
+
id: message.id,
|
|
352
|
+
from: message.from,
|
|
353
|
+
to: message.to,
|
|
354
|
+
type: message.type,
|
|
355
|
+
channel: message.channel,
|
|
356
|
+
content: message.content,
|
|
357
|
+
}, message.from);
|
|
358
|
+
if (observability?.messageLogging) {
|
|
359
|
+
logger.info('[Swarm] message', {
|
|
360
|
+
swarm: this.config.name,
|
|
361
|
+
from: message.from,
|
|
362
|
+
to: message.to,
|
|
363
|
+
type: message.type,
|
|
364
|
+
channel: message.channel,
|
|
365
|
+
content: message.content,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
this.blackboard.onWrite((write) => {
|
|
370
|
+
this.events.emit('blackboard:write', {
|
|
371
|
+
section: write.section,
|
|
372
|
+
version: write.version,
|
|
373
|
+
writtenBy: write.agentName,
|
|
374
|
+
deleted: write.deleted ?? false,
|
|
375
|
+
}, write.agentName);
|
|
376
|
+
if (observability?.blackboardLogging) {
|
|
377
|
+
logger.info('[Swarm] blackboard write', {
|
|
378
|
+
swarm: this.config.name,
|
|
379
|
+
section: write.section,
|
|
380
|
+
version: write.version,
|
|
381
|
+
writtenBy: write.agentName,
|
|
382
|
+
deleted: write.deleted ?? false,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
collectIncomingMessages(agentName) {
|
|
388
|
+
const unread = this.messageBus.getUnreadMessages(agentName);
|
|
389
|
+
if (unread.length === 0)
|
|
390
|
+
return null;
|
|
391
|
+
const ids = unread.map((m) => m.id);
|
|
392
|
+
this.messageBus.markAsRead(agentName, ids);
|
|
393
|
+
this.events.emit('message:received', { agentName, count: unread.length, messageIds: ids }, agentName);
|
|
394
|
+
const formatted = unread.map((m) => {
|
|
395
|
+
const timestamp = new Date(m.timestamp).toISOString();
|
|
396
|
+
return `[${timestamp}] ${m.from} → ${m.to}: ${m.content}`;
|
|
397
|
+
});
|
|
398
|
+
return `\n--- Incoming Messages ---\n${formatted.join('\n')}\n---`;
|
|
399
|
+
}
|
|
400
|
+
buildNegotiationContext(agentName) {
|
|
401
|
+
if (!this.blackboard.has('negotiation'))
|
|
402
|
+
return null;
|
|
403
|
+
const state = this.blackboard.read('negotiation');
|
|
404
|
+
const pendingOffers = state.offers.filter((o) => o.status === 'pending');
|
|
405
|
+
const offersToMe = pendingOffers.filter((o) => {
|
|
406
|
+
const recipients = Array.isArray(o.to) ? o.to : [o.to];
|
|
407
|
+
return recipients.includes(agentName);
|
|
408
|
+
});
|
|
409
|
+
const myOffers = pendingOffers.filter((o) => o.from === agentName);
|
|
410
|
+
return {
|
|
411
|
+
phase: state.phase,
|
|
412
|
+
round: state.round,
|
|
413
|
+
maxRounds: state.maxRounds,
|
|
414
|
+
isMyTurn: state.currentTurn === agentName || state.currentTurn === null,
|
|
415
|
+
currentTurn: state.currentTurn,
|
|
416
|
+
offersAwaitingMyResponse: offersToMe.map((o) => ({
|
|
417
|
+
id: o.id,
|
|
418
|
+
from: o.from,
|
|
419
|
+
reasoning: o.reasoning,
|
|
420
|
+
terms: o.terms,
|
|
421
|
+
})),
|
|
422
|
+
myPendingOffers: myOffers.map((o) => ({
|
|
423
|
+
id: o.id,
|
|
424
|
+
to: o.to,
|
|
425
|
+
status: o.status,
|
|
426
|
+
})),
|
|
427
|
+
myInterests: state.interests[agentName],
|
|
428
|
+
coalitions: state.coalitions.filter((c) => c.members.includes(agentName) || c.status === 'forming'),
|
|
429
|
+
hasAgreement: !!state.agreement,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
export function computeBackoffDelay(backoff, attempt, initialDelay, maxDelay) {
|
|
434
|
+
switch (backoff) {
|
|
435
|
+
case 'exponential':
|
|
436
|
+
return Math.min(initialDelay * Math.pow(2, attempt - 1), maxDelay);
|
|
437
|
+
case 'linear':
|
|
438
|
+
return Math.min(initialDelay * attempt, maxDelay);
|
|
439
|
+
default:
|
|
440
|
+
return Math.min(initialDelay, maxDelay);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function minDefined(...values) {
|
|
444
|
+
const defined = values.filter((v) => v !== undefined);
|
|
445
|
+
return defined.length > 0 ? Math.min(...defined) : undefined;
|
|
446
|
+
}
|
|
447
|
+
function sleep(ms) {
|
|
448
|
+
if (ms <= 0)
|
|
449
|
+
return Promise.resolve();
|
|
450
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
451
|
+
}
|
|
452
|
+
export function toError(error) {
|
|
453
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
454
|
+
}
|
|
455
|
+
//# sourceMappingURL=base-coordinator.js.map
|