@cogitator-ai/swarms 0.4.20 → 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 +71 -52
- 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/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 +81 -46
- package/dist/communication/blackboard.js.map +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 +11 -5
- package/dist/communication/redis-blackboard.d.ts.map +1 -1
- package/dist/communication/redis-blackboard.js +159 -116
- package/dist/communication/redis-blackboard.js.map +1 -1
- package/dist/communication/redis-event-emitter.d.ts +12 -0
- package/dist/communication/redis-event-emitter.d.ts.map +1 -1
- package/dist/communication/redis-event-emitter.js +96 -54
- package/dist/communication/redis-event-emitter.js.map +1 -1
- package/dist/communication/redis-message-bus.d.ts +11 -6
- package/dist/communication/redis-message-bus.d.ts.map +1 -1
- package/dist/communication/redis-message-bus.js +88 -77
- 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 -340
- package/dist/coordinator.js.map +1 -1
- package/dist/distributed/distributed-coordinator.d.ts +54 -51
- package/dist/distributed/distributed-coordinator.d.ts.map +1 -1
- package/dist/distributed/distributed-coordinator.js +166 -284
- 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.map +1 -1
- package/dist/resources/circuit-breaker.js +3 -4
- package/dist/resources/circuit-breaker.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/consensus.d.ts +12 -0
- package/dist/strategies/consensus.d.ts.map +1 -1
- package/dist/strategies/consensus.js +75 -47
- package/dist/strategies/consensus.js.map +1 -1
- package/dist/strategies/debate.d.ts.map +1 -1
- package/dist/strategies/debate.js +18 -8
- package/dist/strategies/debate.js.map +1 -1
- package/dist/strategies/hierarchical.d.ts.map +1 -1
- package/dist/strategies/hierarchical.js +29 -14
- package/dist/strategies/hierarchical.js.map +1 -1
- package/dist/strategies/negotiation/approval.d.ts.map +1 -1
- package/dist/strategies/negotiation/approval.js +22 -19
- package/dist/strategies/negotiation/approval.js.map +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 +276 -141
- package/dist/strategies/negotiation-strategy.js.map +1 -1
- package/dist/strategies/pipeline.js +6 -6
- package/dist/strategies/pipeline.js.map +1 -1
- package/dist/swarm.d.ts +25 -11
- package/dist/swarm.d.ts.map +1 -1
- package/dist/swarm.js +195 -121
- 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 -12
- package/dist/tools/blackboard.js.map +1 -1
- package/dist/tools/delegation.d.ts +17 -4
- package/dist/tools/delegation.d.ts.map +1 -1
- package/dist/tools/delegation.js +95 -88
- 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 +9 -4
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/messaging.d.ts +38 -6
- package/dist/tools/messaging.d.ts.map +1 -1
- package/dist/tools/messaging.js +118 -41
- 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 +138 -115
- 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 +55 -98
- package/dist/workflow/swarm-node.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,10 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Blackboard for shared state between agents
|
|
3
3
|
*/
|
|
4
|
+
import { invokeSafely } from '../utils/invoke.js';
|
|
5
|
+
export function isObservableBlackboard(blackboard) {
|
|
6
|
+
return typeof blackboard.onWrite === 'function';
|
|
7
|
+
}
|
|
8
|
+
export class BlackboardListeners {
|
|
9
|
+
label;
|
|
10
|
+
sectionHandlers = new Map();
|
|
11
|
+
writeListeners = new Set();
|
|
12
|
+
constructor(label) {
|
|
13
|
+
this.label = label;
|
|
14
|
+
}
|
|
15
|
+
subscribe(section, handler) {
|
|
16
|
+
let handlers = this.sectionHandlers.get(section);
|
|
17
|
+
if (!handlers) {
|
|
18
|
+
handlers = new Set();
|
|
19
|
+
this.sectionHandlers.set(section, handlers);
|
|
20
|
+
}
|
|
21
|
+
handlers.add(handler);
|
|
22
|
+
return () => {
|
|
23
|
+
const current = this.sectionHandlers.get(section);
|
|
24
|
+
if (!current)
|
|
25
|
+
return;
|
|
26
|
+
current.delete(handler);
|
|
27
|
+
if (current.size === 0) {
|
|
28
|
+
this.sectionHandlers.delete(section);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
onWrite(listener) {
|
|
33
|
+
this.writeListeners.add(listener);
|
|
34
|
+
return () => {
|
|
35
|
+
this.writeListeners.delete(listener);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
notify(write) {
|
|
39
|
+
if (!write.deleted) {
|
|
40
|
+
for (const handler of [...(this.sectionHandlers.get(write.section) ?? [])]) {
|
|
41
|
+
invokeSafely(handler, [write.data, write.agentName], `${this.label} Handler error`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const listener of [...this.writeListeners]) {
|
|
45
|
+
invokeSafely(listener, [write], `${this.label} Write listener error`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
4
49
|
export class InMemoryBlackboard {
|
|
5
50
|
sections = new Map();
|
|
6
51
|
history = new Map();
|
|
7
|
-
|
|
52
|
+
listeners = new BlackboardListeners('[Blackboard]');
|
|
8
53
|
config;
|
|
9
54
|
constructor(config) {
|
|
10
55
|
this.config = config;
|
|
@@ -29,9 +74,7 @@ export class InMemoryBlackboard {
|
|
|
29
74
|
}
|
|
30
75
|
}
|
|
31
76
|
read(section) {
|
|
32
|
-
|
|
33
|
-
throw new Error('Blackboard is not enabled');
|
|
34
|
-
}
|
|
77
|
+
this.assertEnabled();
|
|
35
78
|
const sec = this.sections.get(section);
|
|
36
79
|
if (!sec) {
|
|
37
80
|
throw new Error(`Blackboard section '${section}' not found`);
|
|
@@ -39,34 +82,29 @@ export class InMemoryBlackboard {
|
|
|
39
82
|
return sec.data;
|
|
40
83
|
}
|
|
41
84
|
write(section, data, agentName) {
|
|
42
|
-
|
|
43
|
-
throw new Error('Blackboard is not enabled');
|
|
44
|
-
}
|
|
85
|
+
this.assertEnabled();
|
|
45
86
|
const existing = this.sections.get(section);
|
|
46
87
|
const version = existing ? existing.version + 1 : 1;
|
|
47
88
|
const timestamp = Date.now();
|
|
48
|
-
|
|
89
|
+
this.sections.set(section, {
|
|
49
90
|
name: section,
|
|
50
91
|
data,
|
|
51
92
|
lastModified: timestamp,
|
|
52
93
|
modifiedBy: agentName,
|
|
53
94
|
version,
|
|
54
|
-
};
|
|
55
|
-
this.sections.set(section, newSection);
|
|
95
|
+
});
|
|
56
96
|
if (this.config.trackHistory) {
|
|
57
|
-
|
|
58
|
-
|
|
97
|
+
let entries = this.history.get(section);
|
|
98
|
+
if (!entries) {
|
|
99
|
+
entries = [];
|
|
100
|
+
this.history.set(section, entries);
|
|
59
101
|
}
|
|
60
|
-
|
|
61
|
-
value: data,
|
|
62
|
-
writtenBy: agentName,
|
|
63
|
-
timestamp,
|
|
64
|
-
version,
|
|
65
|
-
});
|
|
102
|
+
entries.push({ value: data, writtenBy: agentName, timestamp, version });
|
|
66
103
|
}
|
|
67
|
-
this.
|
|
104
|
+
this.listeners.notify({ section, data, agentName, version });
|
|
68
105
|
}
|
|
69
106
|
append(section, item, agentName) {
|
|
107
|
+
this.assertEnabled();
|
|
70
108
|
const current = this.sections.get(section);
|
|
71
109
|
if (!current) {
|
|
72
110
|
this.write(section, [item], agentName);
|
|
@@ -75,31 +113,30 @@ export class InMemoryBlackboard {
|
|
|
75
113
|
if (!Array.isArray(current.data)) {
|
|
76
114
|
throw new Error(`Section '${section}' is not an array, cannot append`);
|
|
77
115
|
}
|
|
78
|
-
|
|
79
|
-
this.write(section, newData, agentName);
|
|
116
|
+
this.write(section, [...current.data, item], agentName);
|
|
80
117
|
}
|
|
81
118
|
has(section) {
|
|
82
119
|
return this.sections.has(section);
|
|
83
120
|
}
|
|
84
121
|
delete(section) {
|
|
122
|
+
const existing = this.sections.get(section);
|
|
85
123
|
this.sections.delete(section);
|
|
86
124
|
this.history.delete(section);
|
|
87
|
-
|
|
125
|
+
if (existing) {
|
|
126
|
+
this.listeners.notify({
|
|
127
|
+
section,
|
|
128
|
+
data: undefined,
|
|
129
|
+
agentName: 'system',
|
|
130
|
+
version: existing.version,
|
|
131
|
+
deleted: true,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
88
134
|
}
|
|
89
135
|
subscribe(section, handler) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.
|
|
94
|
-
return () => {
|
|
95
|
-
const handlers = this.subscriptions.get(section);
|
|
96
|
-
if (handlers) {
|
|
97
|
-
handlers.delete(handler);
|
|
98
|
-
if (handlers.size === 0) {
|
|
99
|
-
this.subscriptions.delete(section);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
};
|
|
136
|
+
return this.listeners.subscribe(section, handler);
|
|
137
|
+
}
|
|
138
|
+
onWrite(listener) {
|
|
139
|
+
return this.listeners.onWrite(listener);
|
|
103
140
|
}
|
|
104
141
|
getSections() {
|
|
105
142
|
return Array.from(this.sections.keys());
|
|
@@ -108,21 +145,19 @@ export class InMemoryBlackboard {
|
|
|
108
145
|
return this.sections.get(section);
|
|
109
146
|
}
|
|
110
147
|
getHistory(section) {
|
|
111
|
-
return this.history.get(section) ?? [];
|
|
148
|
+
return [...(this.history.get(section) ?? [])];
|
|
112
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Remove all sections and history. Subscriptions are preserved so listeners
|
|
152
|
+
* keep working across swarm resets.
|
|
153
|
+
*/
|
|
113
154
|
clear() {
|
|
114
155
|
this.sections.clear();
|
|
115
156
|
this.history.clear();
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (handlers) {
|
|
121
|
-
for (const handler of handlers) {
|
|
122
|
-
void Promise.resolve(handler(data, agentName)).catch((error) => {
|
|
123
|
-
console.warn('[Blackboard] Handler error:', error);
|
|
124
|
-
});
|
|
125
|
-
}
|
|
157
|
+
}
|
|
158
|
+
assertEnabled() {
|
|
159
|
+
if (!this.config.enabled) {
|
|
160
|
+
throw new Error('Blackboard is not enabled');
|
|
126
161
|
}
|
|
127
162
|
}
|
|
128
163
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blackboard.js","sourceRoot":"","sources":["../../src/communication/blackboard.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"blackboard.js","sourceRoot":"","sources":["../../src/communication/blackboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-emitter.d.ts","sourceRoot":"","sources":["../../src/communication/event-emitter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,UAAU,EACV,iBAAiB,EAClB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"event-emitter.d.ts","sourceRoot":"","sources":["../../src/communication/event-emitter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,UAAU,EACV,iBAAiB,EAClB,MAAM,qBAAqB,CAAC;AAG7B,qBAAa,qBAAsB,YAAW,iBAAiB;IAC7D,OAAO,CAAC,QAAQ,CAA2D;IAC3E,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,SAAO;IAI5B,EAAE,CAAC,KAAK,EAAE,cAAc,GAAG,GAAG,EAAE,OAAO,EAAE,iBAAiB,GAAG,MAAM,IAAI;IASvE,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,GAAG,EAAE,OAAO,EAAE,iBAAiB,GAAG,MAAM,IAAI;IAQzE,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAuBrE,GAAG,CAAC,KAAK,EAAE,cAAc,GAAG,GAAG,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAUlE,kBAAkB,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,IAAI;IAQhD,SAAS,IAAI,UAAU,EAAE;IAIzB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,EAAE;IAInD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE;IAIjD,WAAW,IAAI,IAAI;CAGpB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Event emitter for swarm coordination
|
|
3
3
|
*/
|
|
4
|
+
import { invokeSafely } from '../utils/invoke.js';
|
|
4
5
|
export class SwarmEventEmitterImpl {
|
|
5
6
|
handlers = new Map();
|
|
6
7
|
events = [];
|
|
@@ -18,9 +19,7 @@ export class SwarmEventEmitterImpl {
|
|
|
18
19
|
once(event, handler) {
|
|
19
20
|
const wrapper = (e) => {
|
|
20
21
|
this.off(event, wrapper);
|
|
21
|
-
|
|
22
|
-
console.warn('[SwarmEventEmitter] Once handler error:', error);
|
|
23
|
-
});
|
|
22
|
+
invokeSafely(handler, [e], '[SwarmEventEmitter] Once handler error');
|
|
24
23
|
};
|
|
25
24
|
return this.on(event, wrapper);
|
|
26
25
|
}
|
|
@@ -35,21 +34,11 @@ export class SwarmEventEmitterImpl {
|
|
|
35
34
|
if (this.events.length > this.maxEvents) {
|
|
36
35
|
this.events = this.events.slice(-this.maxEvents);
|
|
37
36
|
}
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
for (const handler of handlers) {
|
|
41
|
-
void Promise.resolve(handler(swarmEvent)).catch((error) => {
|
|
42
|
-
console.warn('[SwarmEventEmitter] Handler error:', error);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
37
|
+
for (const handler of [...(this.handlers.get(event) ?? [])]) {
|
|
38
|
+
invokeSafely(handler, [swarmEvent], '[SwarmEventEmitter] Handler error');
|
|
45
39
|
}
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
for (const handler of wildcardHandlers) {
|
|
49
|
-
void Promise.resolve(handler(swarmEvent)).catch((error) => {
|
|
50
|
-
console.warn('[SwarmEventEmitter] Wildcard handler error:', error);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
40
|
+
for (const handler of [...(this.handlers.get('*') ?? [])]) {
|
|
41
|
+
invokeSafely(handler, [swarmEvent], '[SwarmEventEmitter] Wildcard handler error');
|
|
53
42
|
}
|
|
54
43
|
}
|
|
55
44
|
off(event, handler) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-emitter.js","sourceRoot":"","sources":["../../src/communication/event-emitter.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"event-emitter.js","sourceRoot":"","sources":["../../src/communication/event-emitter.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Communication primitives for swarm coordination
|
|
3
3
|
*/
|
|
4
4
|
export { SwarmEventEmitterImpl } from './event-emitter.js';
|
|
5
|
-
export { InMemoryMessageBus, createMessageBus } from './message-bus.js';
|
|
6
|
-
export { InMemoryBlackboard, createBlackboard } from './blackboard.js';
|
|
5
|
+
export { InMemoryMessageBus, createMessageBus, isReadTrackingMessageBus, type ReadTrackingMessageBus, type MessageListener, } from './message-bus.js';
|
|
6
|
+
export { InMemoryBlackboard, createBlackboard, isObservableBlackboard, type ObservableBlackboard, type BlackboardWrite, type BlackboardWriteListener, type BlackboardSectionHandler, } from './blackboard.js';
|
|
7
7
|
export { RedisMessageBus, type RedisMessageBusOptions } from './redis-message-bus.js';
|
|
8
8
|
export { RedisBlackboard, type RedisBlackboardOptions } from './redis-blackboard.js';
|
|
9
9
|
export { RedisSwarmEventEmitter, type RedisEventEmitterOptions } from './redis-event-emitter.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/communication/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/communication/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,GAC9B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAE,sBAAsB,EAAE,KAAK,wBAAwB,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Communication primitives for swarm coordination
|
|
3
3
|
*/
|
|
4
4
|
export { SwarmEventEmitterImpl } from './event-emitter.js';
|
|
5
|
-
export { InMemoryMessageBus, createMessageBus } from './message-bus.js';
|
|
6
|
-
export { InMemoryBlackboard, createBlackboard } from './blackboard.js';
|
|
5
|
+
export { InMemoryMessageBus, createMessageBus, isReadTrackingMessageBus, } from './message-bus.js';
|
|
6
|
+
export { InMemoryBlackboard, createBlackboard, isObservableBlackboard, } from './blackboard.js';
|
|
7
7
|
export { RedisMessageBus } from './redis-message-bus.js';
|
|
8
8
|
export { RedisBlackboard } from './redis-blackboard.js';
|
|
9
9
|
export { RedisSwarmEventEmitter } from './redis-event-emitter.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/communication/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/communication/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,GAGzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,GAKvB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,eAAe,EAA+B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,eAAe,EAA+B,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAE,sBAAsB,EAAiC,MAAM,0BAA0B,CAAC"}
|
|
@@ -2,22 +2,65 @@
|
|
|
2
2
|
* Message bus for agent-to-agent communication
|
|
3
3
|
*/
|
|
4
4
|
import type { MessageBus, MessageBusConfig, SwarmMessage } from '@cogitator-ai/types';
|
|
5
|
-
export
|
|
5
|
+
export type MessageListener = (msg: SwarmMessage) => void;
|
|
6
|
+
/**
|
|
7
|
+
* Message bus that remembers which messages each agent has already consumed.
|
|
8
|
+
*/
|
|
9
|
+
export interface ReadTrackingMessageBus extends MessageBus {
|
|
10
|
+
markAsRead(agentName: string, messageIds: readonly string[]): void;
|
|
11
|
+
resetTurnCounts(agentName?: string): void;
|
|
12
|
+
onMessage(listener: MessageListener): () => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function isReadTrackingMessageBus(bus: MessageBus): bus is ReadTrackingMessageBus;
|
|
15
|
+
export declare function isMessageForAgent(message: SwarmMessage, agentName: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Shared bookkeeping for message bus implementations: per-turn quotas,
|
|
18
|
+
* per-agent read receipts and bus-wide listeners.
|
|
19
|
+
*/
|
|
20
|
+
export declare class MessageBusState {
|
|
21
|
+
private readonly label;
|
|
22
|
+
private turnCounts;
|
|
23
|
+
private readReceipts;
|
|
24
|
+
private listeners;
|
|
25
|
+
constructor(label: string);
|
|
26
|
+
consumeTurnQuota(config: MessageBusConfig, from: string): void;
|
|
27
|
+
resetTurnCounts(agentName?: string): void;
|
|
28
|
+
markAsRead(agentName: string, messageIds: readonly string[]): void;
|
|
29
|
+
isRead(agentName: string, messageId: string): boolean;
|
|
30
|
+
forgetMessages(messageIds: readonly string[]): void;
|
|
31
|
+
onMessage(listener: MessageListener): () => void;
|
|
32
|
+
notifyListeners(message: SwarmMessage): void;
|
|
33
|
+
clear(): void;
|
|
34
|
+
}
|
|
35
|
+
export declare function notifyMessageSubscribers(subscriptions: Map<string, Set<MessageListener>>, message: SwarmMessage, label: string): void;
|
|
36
|
+
export declare function addSubscription(subscriptions: Map<string, Set<MessageListener>>, agentName: string, handler: MessageListener): () => void;
|
|
37
|
+
export declare class InMemoryMessageBus implements ReadTrackingMessageBus {
|
|
6
38
|
private messages;
|
|
7
39
|
private subscriptions;
|
|
8
40
|
private config;
|
|
9
|
-
private
|
|
41
|
+
private state;
|
|
10
42
|
constructor(config: MessageBusConfig);
|
|
11
43
|
send(message: Omit<SwarmMessage, 'id' | 'timestamp'>): Promise<SwarmMessage>;
|
|
12
44
|
broadcast(from: string, content: string, channel?: string): Promise<void>;
|
|
13
|
-
subscribe(agentName: string, handler:
|
|
45
|
+
subscribe(agentName: string, handler: MessageListener): () => void;
|
|
46
|
+
/**
|
|
47
|
+
* Listen to every message sent through the bus, regardless of recipient.
|
|
48
|
+
*/
|
|
49
|
+
onMessage(listener: MessageListener): () => void;
|
|
14
50
|
getMessages(agentName: string, limit?: number): SwarmMessage[];
|
|
15
51
|
getConversation(agent1: string, agent2: string): SwarmMessage[];
|
|
16
52
|
getAllMessages(): SwarmMessage[];
|
|
53
|
+
/**
|
|
54
|
+
* Messages addressed to the agent (directly or via broadcast) that it has not read yet.
|
|
55
|
+
* Use {@link markAsRead} once the messages have been delivered to the agent.
|
|
56
|
+
*/
|
|
17
57
|
getUnreadMessages(agentName: string): SwarmMessage[];
|
|
58
|
+
markAsRead(agentName: string, messageIds: readonly string[]): void;
|
|
18
59
|
clear(): void;
|
|
19
|
-
|
|
20
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Reset per-turn message quotas for one agent, or for all agents when omitted.
|
|
62
|
+
*/
|
|
63
|
+
resetTurnCounts(agentName?: string): void;
|
|
21
64
|
}
|
|
22
65
|
export declare function createMessageBus(config?: Partial<MessageBusConfig>): MessageBus;
|
|
23
66
|
//# sourceMappingURL=message-bus.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-bus.d.ts","sourceRoot":"","sources":["../../src/communication/message-bus.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"message-bus.d.ts","sourceRoot":"","sources":["../../src/communication/message-bus.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,11 +2,120 @@
|
|
|
2
2
|
* Message bus for agent-to-agent communication
|
|
3
3
|
*/
|
|
4
4
|
import { nanoid } from 'nanoid';
|
|
5
|
+
import { invokeSafely } from '../utils/invoke.js';
|
|
6
|
+
export function isReadTrackingMessageBus(bus) {
|
|
7
|
+
const candidate = bus;
|
|
8
|
+
return (typeof candidate.markAsRead === 'function' &&
|
|
9
|
+
typeof candidate.resetTurnCounts === 'function' &&
|
|
10
|
+
typeof candidate.onMessage === 'function');
|
|
11
|
+
}
|
|
12
|
+
export function isMessageForAgent(message, agentName) {
|
|
13
|
+
return (message.to === agentName || message.to === 'broadcast') && message.from !== agentName;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Shared bookkeeping for message bus implementations: per-turn quotas,
|
|
17
|
+
* per-agent read receipts and bus-wide listeners.
|
|
18
|
+
*/
|
|
19
|
+
export class MessageBusState {
|
|
20
|
+
label;
|
|
21
|
+
turnCounts = new Map();
|
|
22
|
+
readReceipts = new Map();
|
|
23
|
+
listeners = new Set();
|
|
24
|
+
constructor(label) {
|
|
25
|
+
this.label = label;
|
|
26
|
+
}
|
|
27
|
+
consumeTurnQuota(config, from) {
|
|
28
|
+
if (!config.maxMessagesPerTurn)
|
|
29
|
+
return;
|
|
30
|
+
const count = this.turnCounts.get(from) ?? 0;
|
|
31
|
+
if (count >= config.maxMessagesPerTurn) {
|
|
32
|
+
throw new Error(`Agent ${from} exceeded max messages per turn (${config.maxMessagesPerTurn})`);
|
|
33
|
+
}
|
|
34
|
+
this.turnCounts.set(from, count + 1);
|
|
35
|
+
}
|
|
36
|
+
resetTurnCounts(agentName) {
|
|
37
|
+
if (agentName === undefined) {
|
|
38
|
+
this.turnCounts.clear();
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
this.turnCounts.delete(agentName);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
markAsRead(agentName, messageIds) {
|
|
45
|
+
let receipts = this.readReceipts.get(agentName);
|
|
46
|
+
if (!receipts) {
|
|
47
|
+
receipts = new Set();
|
|
48
|
+
this.readReceipts.set(agentName, receipts);
|
|
49
|
+
}
|
|
50
|
+
for (const id of messageIds) {
|
|
51
|
+
receipts.add(id);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
isRead(agentName, messageId) {
|
|
55
|
+
return this.readReceipts.get(agentName)?.has(messageId) ?? false;
|
|
56
|
+
}
|
|
57
|
+
forgetMessages(messageIds) {
|
|
58
|
+
if (messageIds.length === 0)
|
|
59
|
+
return;
|
|
60
|
+
for (const receipts of this.readReceipts.values()) {
|
|
61
|
+
for (const id of messageIds) {
|
|
62
|
+
receipts.delete(id);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
onMessage(listener) {
|
|
67
|
+
this.listeners.add(listener);
|
|
68
|
+
return () => {
|
|
69
|
+
this.listeners.delete(listener);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
notifyListeners(message) {
|
|
73
|
+
for (const listener of [...this.listeners]) {
|
|
74
|
+
invokeSafely(listener, [message], `${this.label} Listener error`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
clear() {
|
|
78
|
+
this.turnCounts.clear();
|
|
79
|
+
this.readReceipts.clear();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export function notifyMessageSubscribers(subscriptions, message, label) {
|
|
83
|
+
if (message.to !== 'broadcast') {
|
|
84
|
+
for (const handler of [...(subscriptions.get(message.to) ?? [])]) {
|
|
85
|
+
invokeSafely(handler, [message], `${label} Handler error`);
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
for (const [agentName, handlers] of subscriptions) {
|
|
90
|
+
if (agentName === message.from)
|
|
91
|
+
continue;
|
|
92
|
+
for (const handler of [...handlers]) {
|
|
93
|
+
invokeSafely(handler, [message], `${label} Broadcast handler error`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function addSubscription(subscriptions, agentName, handler) {
|
|
98
|
+
let handlers = subscriptions.get(agentName);
|
|
99
|
+
if (!handlers) {
|
|
100
|
+
handlers = new Set();
|
|
101
|
+
subscriptions.set(agentName, handlers);
|
|
102
|
+
}
|
|
103
|
+
handlers.add(handler);
|
|
104
|
+
return () => {
|
|
105
|
+
const current = subscriptions.get(agentName);
|
|
106
|
+
if (!current)
|
|
107
|
+
return;
|
|
108
|
+
current.delete(handler);
|
|
109
|
+
if (current.size === 0) {
|
|
110
|
+
subscriptions.delete(agentName);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
5
114
|
export class InMemoryMessageBus {
|
|
6
115
|
messages = [];
|
|
7
116
|
subscriptions = new Map();
|
|
8
117
|
config;
|
|
9
|
-
|
|
118
|
+
state = new MessageBusState('[MessageBus]');
|
|
10
119
|
constructor(config) {
|
|
11
120
|
this.config = config;
|
|
12
121
|
}
|
|
@@ -17,23 +126,18 @@ export class InMemoryMessageBus {
|
|
|
17
126
|
if (this.config.maxMessageLength && message.content.length > this.config.maxMessageLength) {
|
|
18
127
|
throw new Error(`Message exceeds max length of ${this.config.maxMessageLength} characters`);
|
|
19
128
|
}
|
|
20
|
-
if (this.config.maxMessagesPerTurn) {
|
|
21
|
-
const count = this.agentMessageCounts.get(message.from) ?? 0;
|
|
22
|
-
if (count >= this.config.maxMessagesPerTurn) {
|
|
23
|
-
throw new Error(`Agent ${message.from} exceeded max messages per turn (${this.config.maxMessagesPerTurn})`);
|
|
24
|
-
}
|
|
25
|
-
this.agentMessageCounts.set(message.from, count + 1);
|
|
26
|
-
}
|
|
27
129
|
if (this.config.maxTotalMessages && this.messages.length >= this.config.maxTotalMessages) {
|
|
28
130
|
throw new Error(`Max total messages (${this.config.maxTotalMessages}) reached`);
|
|
29
131
|
}
|
|
132
|
+
this.state.consumeTurnQuota(this.config, message.from);
|
|
30
133
|
const fullMessage = {
|
|
31
134
|
...message,
|
|
32
135
|
id: `msg_${nanoid(12)}`,
|
|
33
136
|
timestamp: Date.now(),
|
|
34
137
|
};
|
|
35
138
|
this.messages.push(fullMessage);
|
|
36
|
-
this.
|
|
139
|
+
notifyMessageSubscribers(this.subscriptions, fullMessage, '[MessageBus]');
|
|
140
|
+
this.state.notifyListeners(fullMessage);
|
|
37
141
|
return fullMessage;
|
|
38
142
|
}
|
|
39
143
|
async broadcast(from, content, channel) {
|
|
@@ -47,19 +151,13 @@ export class InMemoryMessageBus {
|
|
|
47
151
|
});
|
|
48
152
|
}
|
|
49
153
|
subscribe(agentName, handler) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
handlers.delete(handler);
|
|
58
|
-
if (handlers.size === 0) {
|
|
59
|
-
this.subscriptions.delete(agentName);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
};
|
|
154
|
+
return addSubscription(this.subscriptions, agentName, handler);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Listen to every message sent through the bus, regardless of recipient.
|
|
158
|
+
*/
|
|
159
|
+
onMessage(listener) {
|
|
160
|
+
return this.state.onMessage(listener);
|
|
63
161
|
}
|
|
64
162
|
getMessages(agentName, limit) {
|
|
65
163
|
const relevant = this.messages.filter((m) => m.to === agentName || m.to === 'broadcast' || m.from === agentName);
|
|
@@ -74,38 +172,25 @@ export class InMemoryMessageBus {
|
|
|
74
172
|
getAllMessages() {
|
|
75
173
|
return [...this.messages];
|
|
76
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Messages addressed to the agent (directly or via broadcast) that it has not read yet.
|
|
177
|
+
* Use {@link markAsRead} once the messages have been delivered to the agent.
|
|
178
|
+
*/
|
|
77
179
|
getUnreadMessages(agentName) {
|
|
78
|
-
return this.messages.filter((m) => (m
|
|
180
|
+
return this.messages.filter((m) => isMessageForAgent(m, agentName) && !this.state.isRead(agentName, m.id));
|
|
181
|
+
}
|
|
182
|
+
markAsRead(agentName, messageIds) {
|
|
183
|
+
this.state.markAsRead(agentName, messageIds);
|
|
79
184
|
}
|
|
80
185
|
clear() {
|
|
81
186
|
this.messages = [];
|
|
82
|
-
this.
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const handlers = this.subscriptions.get(message.to);
|
|
90
|
-
if (handlers) {
|
|
91
|
-
for (const handler of handlers) {
|
|
92
|
-
void Promise.resolve(handler(message)).catch((error) => {
|
|
93
|
-
console.warn('[MessageBus] Handler error:', error);
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
for (const [agentName, handlers] of this.subscriptions) {
|
|
100
|
-
if (agentName !== message.from) {
|
|
101
|
-
for (const handler of handlers) {
|
|
102
|
-
void Promise.resolve(handler(message)).catch((error) => {
|
|
103
|
-
console.warn('[MessageBus] Broadcast handler error:', error);
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
187
|
+
this.state.clear();
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Reset per-turn message quotas for one agent, or for all agents when omitted.
|
|
191
|
+
*/
|
|
192
|
+
resetTurnCounts(agentName) {
|
|
193
|
+
this.state.resetTurnCounts(agentName);
|
|
109
194
|
}
|
|
110
195
|
}
|
|
111
196
|
export function createMessageBus(config) {
|