claude-flow 2.7.7 → 2.7.8
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/CHANGELOG.md +37 -0
- package/bin/claude-flow +1 -1
- package/dist/src/cli/help-formatter.js +3 -5
- package/dist/src/cli/help-formatter.js.map +1 -1
- package/dist/src/cli/simple-cli.js.map +1 -1
- package/dist/src/cli/simple-commands/mcp.js +0 -8
- package/dist/src/cli/simple-commands/mcp.js.map +1 -1
- package/dist/src/core/version.js +2 -2
- package/dist/src/mcp/mcp-server.js +5 -5
- package/dist/src/mcp/mcp-server.js.map +1 -1
- package/dist/src/memory/swarm-memory.js +421 -340
- package/dist/src/utils/error-handler.js +1 -3
- package/dist/src/utils/error-handler.js.map +1 -1
- package/dist/src/utils/key-redactor.js.map +1 -1
- package/dist/src/utils/metrics-reader.js +10 -0
- package/package.json +1 -1
- package/src/cli/simple-commands/mcp.js +3 -10
- package/src/mcp/mcp-server.js +6 -5
|
@@ -1,399 +1,480 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
enableReplication: true,
|
|
24
|
-
syncInterval: 10000,
|
|
25
|
-
maxEntries: 10000,
|
|
26
|
-
compressionThreshold: 1000,
|
|
27
|
-
enableKnowledgeBase: true,
|
|
28
|
-
enableCrossAgentSharing: true,
|
|
29
|
-
persistencePath: './swarm-memory',
|
|
30
|
-
...config
|
|
31
|
-
};
|
|
32
|
-
this.entries = new Map();
|
|
33
|
-
this.knowledgeBases = new Map();
|
|
34
|
-
this.agentMemories = new Map();
|
|
35
|
-
const eventBus = EventBus.getInstance();
|
|
36
|
-
this.baseMemory = new MemoryManager({
|
|
37
|
-
backend: 'sqlite',
|
|
38
|
-
namespace: this.config.namespace,
|
|
39
|
-
cacheSizeMB: 50,
|
|
40
|
-
syncOnExit: true,
|
|
41
|
-
maxEntries: this.config.maxEntries,
|
|
42
|
-
ttlMinutes: 60
|
|
43
|
-
}, eventBus, this.logger);
|
|
1
|
+
import { SharedMemory } from './shared-memory.js';
|
|
2
|
+
const SWARM_NAMESPACES = {
|
|
3
|
+
AGENTS: 'swarm:agents',
|
|
4
|
+
TASKS: 'swarm:tasks',
|
|
5
|
+
COMMUNICATIONS: 'swarm:communications',
|
|
6
|
+
CONSENSUS: 'swarm:consensus',
|
|
7
|
+
PATTERNS: 'swarm:patterns',
|
|
8
|
+
METRICS: 'swarm:metrics',
|
|
9
|
+
COORDINATION: 'swarm:coordination'
|
|
10
|
+
};
|
|
11
|
+
export class SwarmMemory extends SharedMemory {
|
|
12
|
+
constructor(options = {}){
|
|
13
|
+
super({
|
|
14
|
+
directory: options.directory || '.swarm',
|
|
15
|
+
filename: options.filename || 'swarm-memory.db',
|
|
16
|
+
...options
|
|
17
|
+
});
|
|
18
|
+
this.swarmId = options.swarmId || 'default';
|
|
19
|
+
this.mcpMode = options.mcpMode !== false;
|
|
20
|
+
this.agentCache = new Map();
|
|
21
|
+
this.taskCache = new Map();
|
|
22
|
+
this.patternCache = new Map();
|
|
44
23
|
}
|
|
45
24
|
async initialize() {
|
|
46
|
-
|
|
47
|
-
this.
|
|
48
|
-
await this.
|
|
49
|
-
|
|
50
|
-
|
|
25
|
+
await super.initialize();
|
|
26
|
+
await this._initializeSwarmNamespaces();
|
|
27
|
+
await this._loadSwarmState();
|
|
28
|
+
this.emit('swarm:initialized', {
|
|
29
|
+
swarmId: this.swarmId
|
|
51
30
|
});
|
|
52
|
-
await this.loadMemoryState();
|
|
53
|
-
if (this.config.syncInterval > 0) {
|
|
54
|
-
this.syncTimer = setInterval(()=>{
|
|
55
|
-
this.syncMemoryState();
|
|
56
|
-
}, this.config.syncInterval);
|
|
57
|
-
}
|
|
58
|
-
this.isInitialized = true;
|
|
59
|
-
this.emit('memory:initialized');
|
|
60
31
|
}
|
|
61
|
-
async
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
await this.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
id: entryId,
|
|
76
|
-
agentId,
|
|
77
|
-
type,
|
|
78
|
-
content,
|
|
79
|
-
timestamp: new Date(),
|
|
32
|
+
async storeAgent(agentId, agentData) {
|
|
33
|
+
const key = `agent:${agentId}`;
|
|
34
|
+
const enrichedData = {
|
|
35
|
+
...agentData,
|
|
36
|
+
swarmId: this.swarmId,
|
|
37
|
+
lastUpdated: new Date().toISOString()
|
|
38
|
+
};
|
|
39
|
+
await this.store(key, enrichedData, {
|
|
40
|
+
namespace: SWARM_NAMESPACES.AGENTS,
|
|
41
|
+
tags: [
|
|
42
|
+
'agent',
|
|
43
|
+
agentData.type,
|
|
44
|
+
agentData.status
|
|
45
|
+
],
|
|
80
46
|
metadata: {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
...metadata
|
|
47
|
+
swarmId: this.swarmId,
|
|
48
|
+
agentType: agentData.type
|
|
84
49
|
}
|
|
50
|
+
});
|
|
51
|
+
this.agentCache.set(agentId, enrichedData);
|
|
52
|
+
this.emit('swarm:agentStored', {
|
|
53
|
+
agentId,
|
|
54
|
+
type: agentData.type
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
agentId,
|
|
58
|
+
stored: true
|
|
85
59
|
};
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
60
|
+
}
|
|
61
|
+
async getAgent(agentId) {
|
|
62
|
+
if (this.agentCache.has(agentId)) {
|
|
63
|
+
return this.agentCache.get(agentId);
|
|
89
64
|
}
|
|
90
|
-
|
|
91
|
-
await this.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
65
|
+
const key = `agent:${agentId}`;
|
|
66
|
+
const agent = await this.retrieve(key, SWARM_NAMESPACES.AGENTS);
|
|
67
|
+
if (agent) {
|
|
68
|
+
this.agentCache.set(agentId, agent);
|
|
69
|
+
}
|
|
70
|
+
return agent;
|
|
71
|
+
}
|
|
72
|
+
async listAgents(filter = {}) {
|
|
73
|
+
const agents = await this.list(SWARM_NAMESPACES.AGENTS, {
|
|
74
|
+
limit: filter.limit || 100
|
|
75
|
+
});
|
|
76
|
+
return agents.map((entry)=>entry.value).filter((agent)=>{
|
|
77
|
+
if (filter.type && agent.type !== filter.type) return false;
|
|
78
|
+
if (filter.status && agent.status !== filter.status) return false;
|
|
79
|
+
if (filter.swarmId && agent.swarmId !== filter.swarmId) return false;
|
|
80
|
+
return true;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async storeTask(taskId, taskData) {
|
|
84
|
+
const key = `task:${taskId}`;
|
|
85
|
+
const enrichedData = {
|
|
86
|
+
...taskData,
|
|
87
|
+
swarmId: this.swarmId,
|
|
88
|
+
createdAt: taskData.createdAt || new Date().toISOString(),
|
|
89
|
+
updatedAt: new Date().toISOString()
|
|
90
|
+
};
|
|
91
|
+
await this.store(key, enrichedData, {
|
|
92
|
+
namespace: SWARM_NAMESPACES.TASKS,
|
|
93
|
+
tags: [
|
|
94
|
+
'task',
|
|
95
|
+
taskData.status,
|
|
96
|
+
taskData.priority
|
|
97
|
+
],
|
|
95
98
|
metadata: {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
entryType: type,
|
|
99
|
-
shareLevel: entry.metadata.shareLevel
|
|
99
|
+
swarmId: this.swarmId,
|
|
100
|
+
assignedAgents: taskData.assignedAgents || []
|
|
100
101
|
}
|
|
101
102
|
});
|
|
102
|
-
this.
|
|
103
|
-
this.emit('
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
this.taskCache.set(taskId, enrichedData);
|
|
104
|
+
this.emit('swarm:taskStored', {
|
|
105
|
+
taskId,
|
|
106
|
+
status: taskData.status
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
taskId,
|
|
110
|
+
stored: true
|
|
111
|
+
};
|
|
109
112
|
}
|
|
110
|
-
async
|
|
111
|
-
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
if (query.type) {
|
|
116
|
-
results = results.filter((e)=>e.type === query.type);
|
|
117
|
-
}
|
|
118
|
-
if (query.taskId) {
|
|
119
|
-
results = results.filter((e)=>e.metadata.taskId === query.taskId);
|
|
113
|
+
async updateTaskStatus(taskId, status, result = null) {
|
|
114
|
+
const task = await this.getTask(taskId);
|
|
115
|
+
if (!task) {
|
|
116
|
+
throw new Error(`Task ${taskId} not found`);
|
|
120
117
|
}
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
task.status = status;
|
|
119
|
+
task.updatedAt = new Date().toISOString();
|
|
120
|
+
if (result) {
|
|
121
|
+
task.result = result;
|
|
123
122
|
}
|
|
124
|
-
if (
|
|
125
|
-
|
|
123
|
+
if (status === 'completed') {
|
|
124
|
+
task.completedAt = new Date().toISOString();
|
|
126
125
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (query.limit) {
|
|
138
|
-
results = results.slice(0, query.limit);
|
|
139
|
-
}
|
|
140
|
-
this.logger.debug(`Recalled ${results.length} memories for query`);
|
|
141
|
-
return results;
|
|
126
|
+
await this.storeTask(taskId, task);
|
|
127
|
+
this.emit('swarm:taskStatusUpdated', {
|
|
128
|
+
taskId,
|
|
129
|
+
status
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
taskId,
|
|
133
|
+
status,
|
|
134
|
+
updated: true
|
|
135
|
+
};
|
|
142
136
|
}
|
|
143
|
-
async
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
throw new Error('Memory entry not found');
|
|
147
|
-
}
|
|
148
|
-
if (!this.config.enableCrossAgentSharing) {
|
|
149
|
-
throw new Error('Cross-agent sharing is disabled');
|
|
137
|
+
async getTask(taskId) {
|
|
138
|
+
if (this.taskCache.has(taskId)) {
|
|
139
|
+
return this.taskCache.get(taskId);
|
|
150
140
|
}
|
|
151
|
-
|
|
152
|
-
|
|
141
|
+
const key = `task:${taskId}`;
|
|
142
|
+
const task = await this.retrieve(key, SWARM_NAMESPACES.TASKS);
|
|
143
|
+
if (task) {
|
|
144
|
+
this.taskCache.set(taskId, task);
|
|
153
145
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
146
|
+
return task;
|
|
147
|
+
}
|
|
148
|
+
async storeCommunication(fromAgent, toAgent, message) {
|
|
149
|
+
const commId = `comm:${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
150
|
+
const communication = {
|
|
151
|
+
id: commId,
|
|
152
|
+
fromAgent,
|
|
153
|
+
toAgent,
|
|
154
|
+
message,
|
|
155
|
+
swarmId: this.swarmId,
|
|
156
|
+
timestamp: new Date().toISOString()
|
|
157
|
+
};
|
|
158
|
+
await this.store(commId, communication, {
|
|
159
|
+
namespace: SWARM_NAMESPACES.COMMUNICATIONS,
|
|
160
|
+
ttl: 86400,
|
|
161
|
+
tags: [
|
|
162
|
+
'communication',
|
|
163
|
+
message.type
|
|
164
|
+
],
|
|
157
165
|
metadata: {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
sharedTo: targetAgentId,
|
|
162
|
-
sharedAt: new Date()
|
|
166
|
+
fromAgent,
|
|
167
|
+
toAgent,
|
|
168
|
+
messageType: message.type
|
|
163
169
|
}
|
|
164
|
-
};
|
|
165
|
-
this.entries.set(sharedEntry.id, sharedEntry);
|
|
166
|
-
if (!this.agentMemories.has(targetAgentId)) {
|
|
167
|
-
this.agentMemories.set(targetAgentId, new Set());
|
|
168
|
-
}
|
|
169
|
-
this.agentMemories.get(targetAgentId).add(sharedEntry.id);
|
|
170
|
-
this.logger.info(`Shared memory ${entryId} from ${entry.agentId} to ${targetAgentId}`);
|
|
171
|
-
this.emit('memory:shared', {
|
|
172
|
-
original: entry,
|
|
173
|
-
shared: sharedEntry
|
|
174
170
|
});
|
|
171
|
+
this.emit('swarm:communication', {
|
|
172
|
+
fromAgent,
|
|
173
|
+
toAgent,
|
|
174
|
+
type: message.type
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
id: commId,
|
|
178
|
+
stored: true
|
|
179
|
+
};
|
|
175
180
|
}
|
|
176
|
-
async
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
181
|
+
async storeConsensus(consensusId, decision) {
|
|
182
|
+
const key = `consensus:${consensusId}`;
|
|
183
|
+
const consensusData = {
|
|
184
|
+
...decision,
|
|
185
|
+
swarmId: this.swarmId,
|
|
186
|
+
timestamp: new Date().toISOString()
|
|
187
|
+
};
|
|
188
|
+
await this.store(key, consensusData, {
|
|
189
|
+
namespace: SWARM_NAMESPACES.CONSENSUS,
|
|
190
|
+
tags: [
|
|
191
|
+
'consensus',
|
|
192
|
+
decision.status
|
|
193
|
+
],
|
|
194
|
+
metadata: {
|
|
195
|
+
swarmId: this.swarmId,
|
|
196
|
+
taskId: decision.taskId,
|
|
197
|
+
threshold: decision.threshold
|
|
190
198
|
}
|
|
191
|
-
}
|
|
192
|
-
this.
|
|
199
|
+
});
|
|
200
|
+
this.emit('swarm:consensus', {
|
|
201
|
+
consensusId,
|
|
202
|
+
status: decision.status
|
|
203
|
+
});
|
|
204
|
+
return {
|
|
205
|
+
consensusId,
|
|
206
|
+
stored: true
|
|
207
|
+
};
|
|
193
208
|
}
|
|
194
|
-
async
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
209
|
+
async storePattern(patternId, pattern) {
|
|
210
|
+
const key = `pattern:${patternId}`;
|
|
211
|
+
const patternData = {
|
|
212
|
+
...pattern,
|
|
213
|
+
swarmId: this.swarmId,
|
|
214
|
+
createdAt: new Date().toISOString(),
|
|
215
|
+
usageCount: 0,
|
|
216
|
+
successRate: 0
|
|
217
|
+
};
|
|
218
|
+
await this.store(key, patternData, {
|
|
219
|
+
namespace: SWARM_NAMESPACES.PATTERNS,
|
|
220
|
+
tags: [
|
|
221
|
+
'pattern',
|
|
222
|
+
pattern.type
|
|
223
|
+
],
|
|
201
224
|
metadata: {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
lastUpdated: new Date()
|
|
225
|
+
swarmId: this.swarmId,
|
|
226
|
+
patternType: pattern.type,
|
|
227
|
+
confidence: pattern.confidence || 0
|
|
206
228
|
}
|
|
229
|
+
});
|
|
230
|
+
if (pattern.type === 'coordination' || pattern.type === 'optimization') {
|
|
231
|
+
this.patternCache.set(patternId, patternData);
|
|
232
|
+
}
|
|
233
|
+
this.emit('swarm:patternStored', {
|
|
234
|
+
patternId,
|
|
235
|
+
type: pattern.type
|
|
236
|
+
});
|
|
237
|
+
return {
|
|
238
|
+
patternId,
|
|
239
|
+
stored: true
|
|
207
240
|
};
|
|
208
|
-
this.knowledgeBases.set(kbId, knowledgeBase);
|
|
209
|
-
this.logger.info(`Created knowledge base: ${name} (${kbId})`);
|
|
210
|
-
this.emit('knowledgebase:created', knowledgeBase);
|
|
211
|
-
return kbId;
|
|
212
241
|
}
|
|
213
|
-
async
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return tags.some((tag)=>kb.metadata.expertise.some((exp)=>exp.toLowerCase().includes(tag.toLowerCase()) || tag.toLowerCase().includes(exp.toLowerCase())));
|
|
218
|
-
});
|
|
219
|
-
for (const kb of relevantKBs){
|
|
220
|
-
kb.entries.push(entry);
|
|
221
|
-
kb.metadata.lastUpdated = new Date();
|
|
222
|
-
if (!kb.metadata.contributors.includes(entry.agentId)) {
|
|
223
|
-
kb.metadata.contributors.push(entry.agentId);
|
|
224
|
-
}
|
|
225
|
-
this.logger.debug(`Updated knowledge base ${kb.id} with entry ${entry.id}`);
|
|
242
|
+
async updatePatternMetrics(patternId, success = true) {
|
|
243
|
+
const pattern = await this.getPattern(patternId);
|
|
244
|
+
if (!pattern) {
|
|
245
|
+
throw new Error(`Pattern ${patternId} not found`);
|
|
226
246
|
}
|
|
247
|
+
pattern.usageCount++;
|
|
248
|
+
pattern.lastUsedAt = new Date().toISOString();
|
|
249
|
+
const alpha = 0.1;
|
|
250
|
+
const currentSuccess = success ? 1 : 0;
|
|
251
|
+
pattern.successRate = alpha * currentSuccess + (1 - alpha) * (pattern.successRate || 0);
|
|
252
|
+
await this.storePattern(patternId, pattern);
|
|
253
|
+
return {
|
|
254
|
+
patternId,
|
|
255
|
+
usageCount: pattern.usageCount,
|
|
256
|
+
successRate: pattern.successRate
|
|
257
|
+
};
|
|
227
258
|
}
|
|
228
|
-
async
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (domain && kb.metadata.domain !== domain) continue;
|
|
232
|
-
if (expertise && !expertise.some((exp)=>kb.metadata.expertise.includes(exp))) {
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
allEntries.push(...kb.entries);
|
|
259
|
+
async getPattern(patternId) {
|
|
260
|
+
if (this.patternCache.has(patternId)) {
|
|
261
|
+
return this.patternCache.get(patternId);
|
|
236
262
|
}
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
263
|
+
const key = `pattern:${patternId}`;
|
|
264
|
+
return await this.retrieve(key, SWARM_NAMESPACES.PATTERNS);
|
|
265
|
+
}
|
|
266
|
+
async findBestPatterns(context, limit = 5) {
|
|
267
|
+
const patterns = await this.search({
|
|
268
|
+
namespace: SWARM_NAMESPACES.PATTERNS,
|
|
269
|
+
tags: context.tags,
|
|
270
|
+
limit: 100
|
|
271
|
+
});
|
|
272
|
+
const scored = patterns.map((entry)=>{
|
|
273
|
+
const pattern = entry.value;
|
|
274
|
+
const score = pattern.successRate * 0.7 + (pattern.confidence || 0) * 0.2 + (pattern.usageCount > 0 ? 0.1 : 0);
|
|
275
|
+
return {
|
|
276
|
+
...pattern,
|
|
277
|
+
score
|
|
278
|
+
};
|
|
241
279
|
});
|
|
242
|
-
return
|
|
280
|
+
return scored.sort((a, b)=>b.score - a.score).slice(0, limit);
|
|
243
281
|
}
|
|
244
|
-
async
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
282
|
+
async storeCoordination(key, state) {
|
|
283
|
+
await this.store(key, state, {
|
|
284
|
+
namespace: SWARM_NAMESPACES.COORDINATION,
|
|
285
|
+
ttl: 3600,
|
|
286
|
+
metadata: {
|
|
287
|
+
swarmId: this.swarmId,
|
|
288
|
+
timestamp: new Date().toISOString()
|
|
289
|
+
}
|
|
290
|
+
});
|
|
250
291
|
return {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
knowledgeContributions,
|
|
254
|
-
sharedEntries
|
|
292
|
+
key,
|
|
293
|
+
stored: true
|
|
255
294
|
};
|
|
256
295
|
}
|
|
257
|
-
async
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
this.logger.info(`Loaded ${entriesArray.length} memory entries`);
|
|
274
|
-
} catch (error) {
|
|
275
|
-
this.logger.warn('No existing memory entries found');
|
|
276
|
-
}
|
|
277
|
-
const kbFile = path.join(this.config.persistencePath, 'knowledge-bases.json');
|
|
278
|
-
try {
|
|
279
|
-
const kbData = await fs.readFile(kbFile, 'utf-8');
|
|
280
|
-
const kbArray = JSON.parse(kbData);
|
|
281
|
-
for (const kb of kbArray){
|
|
282
|
-
this.knowledgeBases.set(kb.id, {
|
|
283
|
-
...kb,
|
|
284
|
-
metadata: {
|
|
285
|
-
...kb.metadata,
|
|
286
|
-
lastUpdated: new Date(kb.metadata.lastUpdated)
|
|
287
|
-
},
|
|
288
|
-
entries: kb.entries.map((e)=>({
|
|
289
|
-
...e,
|
|
290
|
-
timestamp: new Date(e.timestamp)
|
|
291
|
-
}))
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
this.logger.info(`Loaded ${kbArray.length} knowledge bases`);
|
|
295
|
-
} catch (error) {
|
|
296
|
-
this.logger.warn('No existing knowledge bases found');
|
|
296
|
+
async getCoordination(key) {
|
|
297
|
+
return await this.retrieve(key, SWARM_NAMESPACES.COORDINATION);
|
|
298
|
+
}
|
|
299
|
+
async storeMetrics(metricsId, metrics) {
|
|
300
|
+
const key = `metrics:${metricsId}`;
|
|
301
|
+
await this.store(key, metrics, {
|
|
302
|
+
namespace: SWARM_NAMESPACES.METRICS,
|
|
303
|
+
ttl: 86400 * 7,
|
|
304
|
+
tags: [
|
|
305
|
+
'metrics',
|
|
306
|
+
metrics.type
|
|
307
|
+
],
|
|
308
|
+
metadata: {
|
|
309
|
+
swarmId: this.swarmId,
|
|
310
|
+
agentId: metrics.agentId,
|
|
311
|
+
timestamp: new Date().toISOString()
|
|
297
312
|
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
|
|
313
|
+
});
|
|
314
|
+
this.emit('swarm:metricsStored', {
|
|
315
|
+
metricsId,
|
|
316
|
+
type: metrics.type
|
|
317
|
+
});
|
|
318
|
+
return {
|
|
319
|
+
metricsId,
|
|
320
|
+
stored: true
|
|
321
|
+
};
|
|
301
322
|
}
|
|
302
|
-
async
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
323
|
+
async getSwarmStats() {
|
|
324
|
+
const baseStats = await this.getStats();
|
|
325
|
+
const agentCount = await this._countNamespace(SWARM_NAMESPACES.AGENTS);
|
|
326
|
+
const taskCount = await this._countNamespace(SWARM_NAMESPACES.TASKS);
|
|
327
|
+
const patternCount = await this._countNamespace(SWARM_NAMESPACES.PATTERNS);
|
|
328
|
+
const activeAgents = Array.from(this.agentCache.values()).filter((agent)=>agent.status === 'active' || agent.status === 'busy').length;
|
|
329
|
+
const tasks = Array.from(this.taskCache.values());
|
|
330
|
+
const taskStats = {
|
|
331
|
+
total: tasks.length,
|
|
332
|
+
pending: tasks.filter((t)=>t.status === 'pending').length,
|
|
333
|
+
inProgress: tasks.filter((t)=>t.status === 'in_progress').length,
|
|
334
|
+
completed: tasks.filter((t)=>t.status === 'completed').length,
|
|
335
|
+
failed: tasks.filter((t)=>t.status === 'failed').length
|
|
336
|
+
};
|
|
337
|
+
return {
|
|
338
|
+
...baseStats,
|
|
339
|
+
swarm: {
|
|
340
|
+
swarmId: this.swarmId,
|
|
341
|
+
agents: {
|
|
342
|
+
total: agentCount,
|
|
343
|
+
active: activeAgents,
|
|
344
|
+
cached: this.agentCache.size
|
|
345
|
+
},
|
|
346
|
+
tasks: taskStats,
|
|
347
|
+
patterns: {
|
|
348
|
+
total: patternCount,
|
|
349
|
+
cached: this.patternCache.size
|
|
350
|
+
},
|
|
351
|
+
namespaces: Object.values(SWARM_NAMESPACES)
|
|
352
|
+
}
|
|
353
|
+
};
|
|
314
354
|
}
|
|
315
|
-
async
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
355
|
+
async cleanupSwarmData(options = {}) {
|
|
356
|
+
const { maxAge = 86400 * 7, keepPatterns = true, keepConsensus = true } = options;
|
|
357
|
+
const cutoffTime = Date.now() - maxAge * 1000;
|
|
358
|
+
let cleaned = 0;
|
|
359
|
+
const comms = await this.list(SWARM_NAMESPACES.COMMUNICATIONS);
|
|
360
|
+
for (const comm of comms){
|
|
361
|
+
if (new Date(comm.value.timestamp).getTime() < cutoffTime) {
|
|
362
|
+
await this.delete(comm.key, SWARM_NAMESPACES.COMMUNICATIONS);
|
|
363
|
+
cleaned++;
|
|
364
|
+
}
|
|
321
365
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
for (const entry of toRemove){
|
|
329
|
-
this.entries.delete(entry.id);
|
|
330
|
-
const agentEntries = this.agentMemories.get(entry.agentId);
|
|
331
|
-
if (agentEntries) {
|
|
332
|
-
agentEntries.delete(entry.id);
|
|
366
|
+
const tasks = await this.list(SWARM_NAMESPACES.TASKS);
|
|
367
|
+
for (const task of tasks){
|
|
368
|
+
if (task.value.status === 'completed' && new Date(task.value.completedAt).getTime() < cutoffTime) {
|
|
369
|
+
await this.delete(task.key, SWARM_NAMESPACES.TASKS);
|
|
370
|
+
this.taskCache.delete(task.value.id);
|
|
371
|
+
cleaned++;
|
|
333
372
|
}
|
|
334
|
-
this.logger.debug(`Removed old memory entry: ${entry.id}`);
|
|
335
373
|
}
|
|
336
|
-
this.
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
for (const entry of entries){
|
|
343
|
-
entriesByType[entry.type] = (entriesByType[entry.type] || 0) + 1;
|
|
344
|
-
entriesByAgent[entry.agentId] = (entriesByAgent[entry.agentId] || 0) + 1;
|
|
374
|
+
const metrics = await this.list(SWARM_NAMESPACES.METRICS);
|
|
375
|
+
for (const metric of metrics){
|
|
376
|
+
if (new Date(metric.createdAt).getTime() < cutoffTime) {
|
|
377
|
+
await this.delete(metric.key, SWARM_NAMESPACES.METRICS);
|
|
378
|
+
cleaned++;
|
|
379
|
+
}
|
|
345
380
|
}
|
|
346
|
-
|
|
381
|
+
this.emit('swarm:cleanup', {
|
|
382
|
+
cleaned,
|
|
383
|
+
maxAge
|
|
384
|
+
});
|
|
347
385
|
return {
|
|
348
|
-
|
|
349
|
-
entriesByType,
|
|
350
|
-
entriesByAgent,
|
|
351
|
-
knowledgeBases: this.knowledgeBases.size,
|
|
352
|
-
memoryUsage
|
|
386
|
+
cleaned
|
|
353
387
|
};
|
|
354
388
|
}
|
|
355
|
-
async
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
389
|
+
async exportSwarmState() {
|
|
390
|
+
const agents = await this.listAgents();
|
|
391
|
+
const tasks = Array.from(this.taskCache.values());
|
|
392
|
+
const patterns = await this.list(SWARM_NAMESPACES.PATTERNS);
|
|
359
393
|
return {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
394
|
+
swarmId: this.swarmId,
|
|
395
|
+
exportedAt: new Date().toISOString(),
|
|
396
|
+
agents: agents,
|
|
397
|
+
tasks: tasks,
|
|
398
|
+
patterns: patterns.map((p)=>p.value),
|
|
399
|
+
statistics: await this.getSwarmStats()
|
|
364
400
|
};
|
|
365
401
|
}
|
|
366
|
-
async
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
402
|
+
async importSwarmState(state) {
|
|
403
|
+
let imported = {
|
|
404
|
+
agents: 0,
|
|
405
|
+
tasks: 0,
|
|
406
|
+
patterns: 0
|
|
407
|
+
};
|
|
408
|
+
if (state.agents) {
|
|
409
|
+
for (const agent of state.agents){
|
|
410
|
+
await this.storeAgent(agent.id, agent);
|
|
411
|
+
imported.agents++;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (state.tasks) {
|
|
415
|
+
for (const task of state.tasks){
|
|
416
|
+
await this.storeTask(task.id, task);
|
|
417
|
+
imported.tasks++;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (state.patterns) {
|
|
421
|
+
for (const pattern of state.patterns){
|
|
422
|
+
await this.storePattern(pattern.id, pattern);
|
|
423
|
+
imported.patterns++;
|
|
371
424
|
}
|
|
372
|
-
this.agentMemories.delete(agentId);
|
|
373
|
-
this.logger.info(`Cleared memory for agent ${agentId}`);
|
|
374
|
-
} else {
|
|
375
|
-
this.entries.clear();
|
|
376
|
-
this.agentMemories.clear();
|
|
377
|
-
this.knowledgeBases.clear();
|
|
378
|
-
this.logger.info('Cleared all swarm memory');
|
|
379
425
|
}
|
|
380
|
-
this.emit('
|
|
381
|
-
|
|
426
|
+
this.emit('swarm:imported', imported);
|
|
427
|
+
return imported;
|
|
428
|
+
}
|
|
429
|
+
async _initializeSwarmNamespaces() {
|
|
430
|
+
await this.store('swarm:metadata', {
|
|
431
|
+
swarmId: this.swarmId,
|
|
432
|
+
createdAt: new Date().toISOString(),
|
|
433
|
+
version: '1.0.0',
|
|
434
|
+
namespaces: Object.values(SWARM_NAMESPACES)
|
|
435
|
+
}, {
|
|
436
|
+
namespace: 'swarm:system'
|
|
382
437
|
});
|
|
383
438
|
}
|
|
384
|
-
async
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
439
|
+
async _loadSwarmState() {
|
|
440
|
+
const agents = await this.list(SWARM_NAMESPACES.AGENTS, {
|
|
441
|
+
limit: 100
|
|
442
|
+
});
|
|
443
|
+
for (const entry of agents){
|
|
444
|
+
if (entry.value.status === 'active' || entry.value.status === 'busy') {
|
|
445
|
+
this.agentCache.set(entry.value.id, entry.value);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
const tasks = await this.search({
|
|
449
|
+
namespace: SWARM_NAMESPACES.TASKS,
|
|
389
450
|
tags: [
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
451
|
+
'in_progress'
|
|
452
|
+
],
|
|
453
|
+
limit: 100
|
|
454
|
+
});
|
|
455
|
+
for (const entry of tasks){
|
|
456
|
+
this.taskCache.set(entry.value.id, entry.value);
|
|
457
|
+
}
|
|
458
|
+
const patterns = await this.list(SWARM_NAMESPACES.PATTERNS, {
|
|
459
|
+
limit: 50
|
|
394
460
|
});
|
|
461
|
+
for (const entry of patterns){
|
|
462
|
+
if (entry.value.confidence > 0.7 || entry.value.successRate > 0.8) {
|
|
463
|
+
this.patternCache.set(entry.value.id, entry.value);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
async _countNamespace(namespace) {
|
|
468
|
+
const stats = await this.getStats();
|
|
469
|
+
return stats.namespaces[namespace]?.count || 0;
|
|
395
470
|
}
|
|
396
|
-
|
|
471
|
+
}
|
|
472
|
+
export function createSwarmMemory(options = {}) {
|
|
473
|
+
return new SwarmMemory(options);
|
|
474
|
+
}
|
|
475
|
+
export default SwarmMemory;
|
|
476
|
+
|
|
477
|
+
//# sourceMappingURL=swarm-memory.js.maptern, limit = 10) {
|
|
397
478
|
const results = [];
|
|
398
479
|
for (const entry of this.entries.values()){
|
|
399
480
|
const entryString = JSON.stringify(entry);
|