agentic-qe 2.5.4 → 2.5.6
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/.claude/commands/aqe-costs.md +509 -0
- package/CHANGELOG.md +128 -0
- package/README.md +1 -1
- package/dist/adapters/MemoryStoreAdapter.d.ts +75 -123
- package/dist/adapters/MemoryStoreAdapter.d.ts.map +1 -1
- package/dist/adapters/MemoryStoreAdapter.js +204 -219
- package/dist/adapters/MemoryStoreAdapter.js.map +1 -1
- package/dist/agents/AccessibilityAllyAgent.d.ts.map +1 -1
- package/dist/agents/AccessibilityAllyAgent.js +17 -1
- package/dist/agents/AccessibilityAllyAgent.js.map +1 -1
- package/dist/agents/BaseAgent.d.ts +18 -250
- package/dist/agents/BaseAgent.d.ts.map +1 -1
- package/dist/agents/BaseAgent.js +122 -520
- package/dist/agents/BaseAgent.js.map +1 -1
- package/dist/agents/SONALifecycleManager.d.ts +226 -0
- package/dist/agents/SONALifecycleManager.d.ts.map +1 -0
- package/dist/agents/SONALifecycleManager.js +563 -0
- package/dist/agents/SONALifecycleManager.js.map +1 -0
- package/dist/agents/index.d.ts +2 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +7 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/utils/generators.d.ts +30 -0
- package/dist/agents/utils/generators.d.ts.map +1 -0
- package/dist/agents/utils/generators.js +44 -0
- package/dist/agents/utils/generators.js.map +1 -0
- package/dist/agents/utils/index.d.ts +10 -0
- package/dist/agents/utils/index.d.ts.map +1 -0
- package/dist/agents/utils/index.js +19 -0
- package/dist/agents/utils/index.js.map +1 -0
- package/dist/agents/utils/validation.d.ts +72 -0
- package/dist/agents/utils/validation.d.ts.map +1 -0
- package/dist/agents/utils/validation.js +75 -0
- package/dist/agents/utils/validation.js.map +1 -0
- package/dist/core/memory/HNSWVectorMemory.js +1 -1
- package/dist/core/memory/SwarmMemoryManager.d.ts +114 -90
- package/dist/core/memory/SwarmMemoryManager.d.ts.map +1 -1
- package/dist/core/memory/SwarmMemoryManager.js +277 -235
- package/dist/core/memory/SwarmMemoryManager.js.map +1 -1
- package/dist/core/metrics/InferenceCostTracker.d.ts +293 -0
- package/dist/core/metrics/InferenceCostTracker.d.ts.map +1 -0
- package/dist/core/metrics/InferenceCostTracker.js +461 -0
- package/dist/core/metrics/InferenceCostTracker.js.map +1 -0
- package/dist/core/metrics/index.d.ts +1 -0
- package/dist/core/metrics/index.d.ts.map +1 -1
- package/dist/core/metrics/index.js +7 -1
- package/dist/core/metrics/index.js.map +1 -1
- package/dist/core/routing/AdaptiveModelRouter.d.ts +17 -0
- package/dist/core/routing/AdaptiveModelRouter.d.ts.map +1 -1
- package/dist/core/routing/AdaptiveModelRouter.js +117 -0
- package/dist/core/routing/AdaptiveModelRouter.js.map +1 -1
- package/dist/core/routing/ModelRules.d.ts +2 -0
- package/dist/core/routing/ModelRules.d.ts.map +1 -1
- package/dist/core/routing/ModelRules.js +82 -0
- package/dist/core/routing/ModelRules.js.map +1 -1
- package/dist/core/routing/types.d.ts +14 -1
- package/dist/core/routing/types.d.ts.map +1 -1
- package/dist/core/routing/types.js +7 -0
- package/dist/core/routing/types.js.map +1 -1
- package/dist/learning/baselines/StandardTaskSuite.d.ts.map +1 -1
- package/dist/learning/baselines/StandardTaskSuite.js +38 -0
- package/dist/learning/baselines/StandardTaskSuite.js.map +1 -1
- package/dist/mcp/server-instructions.d.ts +1 -1
- package/dist/mcp/server-instructions.js +1 -1
- package/dist/mcp/services/AgentRegistry.d.ts +35 -0
- package/dist/mcp/services/AgentRegistry.d.ts.map +1 -1
- package/dist/mcp/services/AgentRegistry.js +126 -1
- package/dist/mcp/services/AgentRegistry.js.map +1 -1
- package/dist/mcp/tools/qe/accessibility/video-vision-analyzer.d.ts +8 -1
- package/dist/mcp/tools/qe/accessibility/video-vision-analyzer.d.ts.map +1 -1
- package/dist/mcp/tools/qe/accessibility/video-vision-analyzer.js +134 -46
- package/dist/mcp/tools/qe/accessibility/video-vision-analyzer.js.map +1 -1
- package/dist/telemetry/metrics/collectors/cost.d.ts.map +1 -1
- package/dist/telemetry/metrics/collectors/cost.js +6 -0
- package/dist/telemetry/metrics/collectors/cost.js.map +1 -1
- package/dist/types/memory-interfaces.d.ts +76 -68
- package/dist/types/memory-interfaces.d.ts.map +1 -1
- package/dist/types/memory-interfaces.js +3 -0
- package/dist/types/memory-interfaces.js.map +1 -1
- package/package.json +9 -2
package/dist/agents/BaseAgent.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* BaseAgent - Abstract base class for all QE agents
|
|
4
|
-
*
|
|
5
|
-
* Based on SPARC Phase 2 Pseudocode and Phase 3 Architecture
|
|
4
|
+
* Phase 2 B1.2: Decomposed with strategy pattern (~500 LOC target)
|
|
6
5
|
*/
|
|
7
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.BaseAgentFactory = exports.BaseAgent = void 0;
|
|
9
|
-
exports.isSwarmMemoryManager = isSwarmMemoryManager;
|
|
10
|
-
exports.validateLearningConfig = validateLearningConfig;
|
|
7
|
+
exports.BaseAgentFactory = exports.BaseAgent = exports.validateLearningConfig = exports.isSwarmMemoryManager = void 0;
|
|
11
8
|
const events_1 = require("events");
|
|
12
|
-
const SecureRandom_js_1 = require("../utils/SecureRandom.js");
|
|
13
9
|
const types_1 = require("../types");
|
|
14
10
|
const hooks_1 = require("../core/hooks");
|
|
15
11
|
const MemoryStoreAdapter_1 = require("../adapters/MemoryStoreAdapter");
|
|
@@ -20,85 +16,27 @@ const AgentLifecycleManager_1 = require("./lifecycle/AgentLifecycleManager");
|
|
|
20
16
|
const AgentCoordinator_1 = require("./coordination/AgentCoordinator");
|
|
21
17
|
const AgentMemoryService_1 = require("./memory/AgentMemoryService");
|
|
22
18
|
const adapters_1 = require("./adapters");
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* This is a runtime check using instanceof. Use this to verify if learning
|
|
28
|
-
* features are available before attempting to use them.
|
|
29
|
-
*
|
|
30
|
-
* Note: This is NOT a TypeScript type guard because MemoryStore and
|
|
31
|
-
* SwarmMemoryManager have incompatible method signatures. After checking
|
|
32
|
-
* with this function, use a type assertion: `store as SwarmMemoryManager`
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```typescript
|
|
36
|
-
* if (isSwarmMemoryManager(config.memoryStore)) {
|
|
37
|
-
* const swarm = config.memoryStore as SwarmMemoryManager;
|
|
38
|
-
* // Use swarm's learning features
|
|
39
|
-
* }
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
function isSwarmMemoryManager(store) {
|
|
43
|
-
return store instanceof SwarmMemoryManager_1.SwarmMemoryManager;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Validate agent config for learning features
|
|
47
|
-
*
|
|
48
|
-
* @remarks
|
|
49
|
-
* Call this early in agent initialization to fail fast with clear error message.
|
|
50
|
-
* This helps developers identify configuration issues immediately rather than
|
|
51
|
-
* discovering disabled learning features at runtime.
|
|
52
|
-
*
|
|
53
|
-
* Issue #137: FleetManager was passing MemoryManager instead of SwarmMemoryManager,
|
|
54
|
-
* causing learning features to be silently disabled for all agents.
|
|
55
|
-
*
|
|
56
|
-
* @param config - Agent configuration to validate
|
|
57
|
-
* @param options - Validation options
|
|
58
|
-
* @param options.throwOnMismatch - If true, throws an error instead of returning warning
|
|
59
|
-
* @returns Validation result with valid flag and optional warning message
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* ```typescript
|
|
63
|
-
* // In agent constructor:
|
|
64
|
-
* const validation = validateLearningConfig(config);
|
|
65
|
-
* if (!validation.valid) {
|
|
66
|
-
* console.warn(validation.warning);
|
|
67
|
-
* }
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
function validateLearningConfig(config, options = {}) {
|
|
71
|
-
const enableLearning = config.enableLearning ?? true;
|
|
72
|
-
if (enableLearning && !isSwarmMemoryManager(config.memoryStore)) {
|
|
73
|
-
const warning = `Learning is enabled but memoryStore is not SwarmMemoryManager. ` +
|
|
74
|
-
`Got ${config.memoryStore.constructor.name}. ` +
|
|
75
|
-
`Learning features (Q-learning, patterns, metrics) will be DISABLED. ` +
|
|
76
|
-
`To fix: Use SwarmMemoryManager or set enableLearning: false.`;
|
|
77
|
-
if (options.throwOnMismatch) {
|
|
78
|
-
throw new Error(warning);
|
|
79
|
-
}
|
|
80
|
-
return { valid: false, warning };
|
|
81
|
-
}
|
|
82
|
-
return { valid: true };
|
|
83
|
-
}
|
|
19
|
+
// Extracted utilities (B1.2)
|
|
20
|
+
const utils_1 = require("./utils");
|
|
21
|
+
Object.defineProperty(exports, "isSwarmMemoryManager", { enumerable: true, get: function () { return utils_1.isSwarmMemoryManager; } });
|
|
22
|
+
Object.defineProperty(exports, "validateLearningConfig", { enumerable: true, get: function () { return utils_1.validateLearningConfig; } });
|
|
84
23
|
class BaseAgent extends events_1.EventEmitter {
|
|
85
24
|
constructor(config) {
|
|
86
25
|
super();
|
|
87
26
|
this.performanceMetrics = { tasksCompleted: 0, averageExecutionTime: 0, errorCount: 0, lastActivity: new Date() };
|
|
88
|
-
this.agentId = { id: config.id ||
|
|
27
|
+
this.agentId = { id: config.id || (0, utils_1.generateAgentId)(config.type), type: config.type, created: new Date() };
|
|
89
28
|
this.capabilities = new Map(config.capabilities.map(cap => [cap.name, cap]));
|
|
90
29
|
this.context = config.context;
|
|
91
30
|
this.memoryStore = config.memoryStore;
|
|
92
31
|
this.eventBus = config.eventBus;
|
|
93
32
|
this.enableLearning = config.enableLearning ?? true;
|
|
94
33
|
this.learningConfig = config.learningConfig;
|
|
95
|
-
// Early validation
|
|
96
|
-
|
|
97
|
-
const validation = validateLearningConfig(config);
|
|
34
|
+
// Early validation (Issue #137)
|
|
35
|
+
const validation = (0, utils_1.validateLearningConfig)(config);
|
|
98
36
|
if (!validation.valid && validation.warning) {
|
|
99
37
|
console.warn(`[${this.agentId.id}] CONFIG WARNING: ${validation.warning}`);
|
|
100
38
|
}
|
|
101
|
-
// Initialize
|
|
39
|
+
// Initialize services
|
|
102
40
|
const memoryAdapter = new MemoryStoreAdapter_1.MemoryStoreAdapter(this.memoryStore);
|
|
103
41
|
this.hookManager = new hooks_1.VerificationHookManager(memoryAdapter);
|
|
104
42
|
this.lifecycleManager = new AgentLifecycleManager_1.AgentLifecycleManager(this.agentId);
|
|
@@ -115,83 +53,47 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
115
53
|
this.setupEventHandlers();
|
|
116
54
|
this.setupLifecycleHooks();
|
|
117
55
|
}
|
|
118
|
-
//
|
|
119
|
-
// Public Interface
|
|
120
|
-
// ============================================================================
|
|
121
|
-
/**
|
|
122
|
-
* Initialize the agent - must be called after construction
|
|
123
|
-
* Thread-safe: Multiple concurrent calls will wait for the first to complete
|
|
124
|
-
*/
|
|
56
|
+
// === Public Interface ===
|
|
125
57
|
async initialize() {
|
|
126
|
-
// Thread-safety: If initialization is in progress, wait for it
|
|
127
58
|
if (this.initializationMutex) {
|
|
128
|
-
console.info(`[${this.agentId.id}] Initialization already in progress, waiting for completion`);
|
|
129
59
|
await this.initializationMutex;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (statusAfterWait === types_1.AgentStatus.ERROR) {
|
|
133
|
-
throw new Error(`Initialization failed (status: ${statusAfterWait})`);
|
|
60
|
+
if (this.lifecycleManager.getStatus() === types_1.AgentStatus.ERROR) {
|
|
61
|
+
throw new Error(`Initialization failed`);
|
|
134
62
|
}
|
|
135
63
|
return;
|
|
136
64
|
}
|
|
137
|
-
// Guard: Skip if already initialized (ACTIVE or IDLE)
|
|
138
65
|
const currentStatus = this.lifecycleManager.getStatus();
|
|
139
|
-
if (currentStatus === types_1.AgentStatus.ACTIVE || currentStatus === types_1.AgentStatus.IDLE)
|
|
140
|
-
console.warn(`[${this.agentId.id}] Agent already initialized (status: ${currentStatus}), skipping`);
|
|
66
|
+
if (currentStatus === types_1.AgentStatus.ACTIVE || currentStatus === types_1.AgentStatus.IDLE)
|
|
141
67
|
return;
|
|
142
|
-
}
|
|
143
|
-
// Create initialization mutex - lock acquired
|
|
144
68
|
let resolveMutex;
|
|
145
|
-
this.initializationMutex = new Promise((resolve) => {
|
|
146
|
-
resolveMutex = resolve;
|
|
147
|
-
});
|
|
69
|
+
this.initializationMutex = new Promise((resolve) => { resolveMutex = resolve; });
|
|
148
70
|
try {
|
|
149
|
-
|
|
150
|
-
if (currentStatus === types_1.AgentStatus.ERROR) {
|
|
151
|
-
console.info(`[${this.agentId.id}] Resetting agent from ERROR state before initialization`);
|
|
71
|
+
if (currentStatus === types_1.AgentStatus.ERROR)
|
|
152
72
|
this.lifecycleManager.reset(false);
|
|
153
|
-
}
|
|
154
|
-
// Delegate lifecycle initialization to lifecycleManager
|
|
155
73
|
await this.lifecycleManager.initialize({
|
|
156
|
-
onPreInitialization:
|
|
157
|
-
await this.executeHook('pre-initialization');
|
|
158
|
-
},
|
|
74
|
+
onPreInitialization: () => this.executeHook('pre-initialization'),
|
|
159
75
|
onPostInitialization: async () => {
|
|
160
|
-
// Load agent knowledge and state
|
|
161
76
|
await this.loadKnowledge();
|
|
162
77
|
const savedState = await this.memoryService.restoreState();
|
|
163
|
-
if (savedState
|
|
78
|
+
if (savedState?.performanceMetrics) {
|
|
164
79
|
this.performanceMetrics = { ...this.performanceMetrics, ...savedState.performanceMetrics };
|
|
165
80
|
}
|
|
166
|
-
// Initialize
|
|
167
|
-
// Issue #137: FleetManager now provides SwarmMemoryManager to enable learning
|
|
81
|
+
// Initialize learning if SwarmMemoryManager
|
|
168
82
|
if (this.enableLearning && this.memoryStore instanceof SwarmMemoryManager_1.SwarmMemoryManager) {
|
|
169
83
|
this.performanceTracker = new PerformanceTracker_1.PerformanceTracker(this.agentId.id, this.memoryStore);
|
|
170
84
|
await this.performanceTracker.initialize();
|
|
171
|
-
// Initialize learning engine for Q-learning
|
|
172
|
-
// ARCHITECTURE (v2.2.0): LearningEngine uses SwarmMemoryManager for ALL persistence
|
|
173
|
-
// All data (experiences, patterns, Q-values) goes to unified .agentic-qe/memory.db
|
|
174
|
-
// No direct database dependency - memoryStore handles all coordination
|
|
175
85
|
this.learningEngine = new LearningEngine_1.LearningEngine(this.agentId.id, this.memoryStore, this.learningConfig);
|
|
176
86
|
await this.learningEngine.initialize();
|
|
177
|
-
// Phase 2 (B1.2): Create learning strategy adapter
|
|
178
|
-
// Only set if not already injected via config
|
|
179
87
|
if (!this.strategies.learning) {
|
|
180
88
|
this.strategies.learning = (0, adapters_1.createLearningAdapter)(this.learningEngine);
|
|
181
89
|
}
|
|
182
90
|
}
|
|
183
|
-
else if (this.enableLearning
|
|
184
|
-
|
|
185
|
-
// Note: Early warning was already emitted in constructor (Issue #137)
|
|
186
|
-
console.warn(`[${this.agentId.id}] Learning enabled but memoryStore is not SwarmMemoryManager. ` +
|
|
187
|
-
`Learning features will be disabled. Expected SwarmMemoryManager, got ${this.memoryStore.constructor.name}`);
|
|
91
|
+
else if (this.enableLearning) {
|
|
92
|
+
console.warn(`[${this.agentId.id}] Learning disabled: memoryStore is ${this.memoryStore.constructor.name}`);
|
|
188
93
|
}
|
|
189
|
-
// Initialize agent-specific components
|
|
190
94
|
await this.initializeComponents();
|
|
191
|
-
// Execute post-initialization hooks
|
|
192
95
|
await this.executeHook('post-initialization');
|
|
193
96
|
this.coordinator.emitEvent('agent.initialized', { agentId: this.agentId });
|
|
194
|
-
// Report initialization to coordination system
|
|
195
97
|
await this.coordinator.reportStatus('initialized', this.performanceMetrics);
|
|
196
98
|
}
|
|
197
99
|
});
|
|
@@ -202,60 +104,39 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
202
104
|
throw error;
|
|
203
105
|
}
|
|
204
106
|
finally {
|
|
205
|
-
// Release mutex lock - allow future initializations
|
|
206
107
|
resolveMutex();
|
|
207
108
|
this.initializationMutex = undefined;
|
|
208
109
|
}
|
|
209
110
|
}
|
|
210
|
-
/**
|
|
211
|
-
* Execute a task assignment with integrated verification hooks
|
|
212
|
-
*/
|
|
213
111
|
async executeTask(assignment) {
|
|
214
112
|
const startTime = Date.now();
|
|
215
113
|
try {
|
|
216
|
-
// Validate task assignment
|
|
217
114
|
this.validateTaskAssignment(assignment);
|
|
218
115
|
this.currentTask = assignment;
|
|
219
|
-
// Phase 2 (B1.2): Use lifecycle strategy for status transitions
|
|
220
116
|
await this.strategies.lifecycle.transitionTo(types_1.AgentStatus.ACTIVE);
|
|
221
|
-
// Execute pre-task hooks with verification
|
|
222
117
|
const preTaskData = { assignment };
|
|
223
118
|
await this.onPreTask(preTaskData);
|
|
224
119
|
await this.executeHook('pre-task', preTaskData);
|
|
225
|
-
// Broadcast task start
|
|
226
120
|
await this.coordinator.broadcastMessage('task-start', assignment);
|
|
227
|
-
// Execute the actual task
|
|
228
121
|
const result = await this.performTask(assignment.task);
|
|
229
|
-
// Execute post-task hooks with validation
|
|
230
122
|
const postTaskData = { assignment, result };
|
|
231
123
|
await this.onPostTask(postTaskData);
|
|
232
124
|
await this.executeHook('post-task', postTaskData);
|
|
233
|
-
// Update performance metrics and store result
|
|
234
125
|
this.updatePerformanceMetrics(startTime, true);
|
|
235
126
|
await this.memoryService.storeTaskResult(assignment.id, result);
|
|
236
127
|
this.currentTask = undefined;
|
|
237
|
-
// Phase 2 (B1.2): Use lifecycle strategy for status transitions
|
|
238
128
|
await this.strategies.lifecycle.transitionTo(types_1.AgentStatus.IDLE);
|
|
239
129
|
return result;
|
|
240
130
|
}
|
|
241
131
|
catch (error) {
|
|
242
132
|
this.updatePerformanceMetrics(startTime, false);
|
|
243
133
|
this.currentTask = undefined;
|
|
244
|
-
|
|
245
|
-
await this.
|
|
246
|
-
|
|
247
|
-
const errorData = {
|
|
248
|
-
assignment,
|
|
249
|
-
error: error
|
|
250
|
-
};
|
|
251
|
-
await this.onTaskError(errorData);
|
|
252
|
-
await this.executeHook('task-error', errorData);
|
|
134
|
+
await this.strategies.lifecycle.transitionTo(types_1.AgentStatus.ERROR, `Task failed: ${error}`);
|
|
135
|
+
await this.onTaskError({ assignment, error: error });
|
|
136
|
+
await this.executeHook('task-error', { assignment, error });
|
|
253
137
|
throw error;
|
|
254
138
|
}
|
|
255
139
|
}
|
|
256
|
-
/**
|
|
257
|
-
* Terminate the agent gracefully
|
|
258
|
-
*/
|
|
259
140
|
async terminate() {
|
|
260
141
|
try {
|
|
261
142
|
await this.lifecycleManager.terminate({
|
|
@@ -277,17 +158,9 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
277
158
|
throw error;
|
|
278
159
|
}
|
|
279
160
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
*/
|
|
283
|
-
getAgentId() {
|
|
284
|
-
return this.agentId;
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Get current agent status and metrics
|
|
288
|
-
*/
|
|
161
|
+
// === Getters ===
|
|
162
|
+
getAgentId() { return this.agentId; }
|
|
289
163
|
getStatus() {
|
|
290
|
-
// Phase 2 (B1.2): Use lifecycle strategy instead of direct manager call
|
|
291
164
|
return {
|
|
292
165
|
agentId: this.agentId,
|
|
293
166
|
status: this.strategies.lifecycle.getStatus(),
|
|
@@ -296,29 +169,25 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
296
169
|
performanceMetrics: { ...this.performanceMetrics }
|
|
297
170
|
};
|
|
298
171
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
172
|
+
hasCapability(name) { return this.capabilities.has(name); }
|
|
173
|
+
getCapability(name) { return this.capabilities.get(name); }
|
|
174
|
+
getCapabilities() { return Array.from(this.capabilities.values()); }
|
|
175
|
+
getStrategies() { return this.strategies; }
|
|
176
|
+
getLifecycleStrategy() { return this.strategies.lifecycle; }
|
|
177
|
+
getMemoryStrategy() { return this.strategies.memory; }
|
|
178
|
+
getLearningStrategy() { return this.strategies.learning; }
|
|
179
|
+
getCoordinationStrategy() { return this.strategies.coordination; }
|
|
180
|
+
// === Event-Driven Coordination ===
|
|
307
181
|
async waitForStatus(status, timeout = 10000) {
|
|
308
|
-
// Phase 2 (B1.2): Use lifecycle strategy for status waiting
|
|
309
|
-
// Strategy provides waitForStatus implementation
|
|
310
182
|
if (typeof this.strategies.lifecycle.waitForStatus === 'function') {
|
|
311
183
|
return this.strategies.lifecycle.waitForStatus(status, timeout);
|
|
312
184
|
}
|
|
313
|
-
// Fallback to event-based implementation
|
|
314
185
|
return new Promise((resolve, reject) => {
|
|
315
|
-
|
|
316
|
-
if (this.strategies.lifecycle.getStatus() === status) {
|
|
186
|
+
if (this.strategies.lifecycle.getStatus() === status)
|
|
317
187
|
return resolve();
|
|
318
|
-
}
|
|
319
188
|
const timer = setTimeout(() => {
|
|
320
189
|
this.removeListener('status-changed', listener);
|
|
321
|
-
reject(new Error(`Agent
|
|
190
|
+
reject(new Error(`Agent did not reach status '${status}' within ${timeout}ms`));
|
|
322
191
|
}, timeout);
|
|
323
192
|
const listener = (newStatus) => {
|
|
324
193
|
if (newStatus === status) {
|
|
@@ -330,146 +199,41 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
330
199
|
this.on('status-changed', listener);
|
|
331
200
|
});
|
|
332
201
|
}
|
|
333
|
-
/**
|
|
334
|
-
* Wait for agent to be ready (initialized and idle)
|
|
335
|
-
* Replaces: await new Promise(resolve => setTimeout(resolve, 5000))
|
|
336
|
-
* Use: await agent.waitForReady()
|
|
337
|
-
*/
|
|
338
202
|
async waitForReady(timeout = 10000) {
|
|
339
|
-
// Phase 2 (B1.2): Use lifecycle strategy
|
|
340
|
-
// Strategy provides waitForReady implementation
|
|
341
203
|
if (typeof this.strategies.lifecycle.waitForReady === 'function') {
|
|
342
204
|
return this.strategies.lifecycle.waitForReady(timeout);
|
|
343
205
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
return; // Already ready
|
|
348
|
-
}
|
|
206
|
+
const status = this.strategies.lifecycle.getStatus();
|
|
207
|
+
if (status === types_1.AgentStatus.IDLE || status === types_1.AgentStatus.ACTIVE)
|
|
208
|
+
return;
|
|
349
209
|
return this.waitForStatus(types_1.AgentStatus.IDLE, timeout);
|
|
350
210
|
}
|
|
351
|
-
/**
|
|
352
|
-
* Wait for a specific event to be emitted
|
|
353
|
-
* Generic event waiter for custom coordination
|
|
354
|
-
*/
|
|
355
211
|
async waitForEvent(eventName, timeout = 10000) {
|
|
356
212
|
return new Promise((resolve, reject) => {
|
|
357
213
|
const timer = setTimeout(() => {
|
|
358
214
|
this.removeListener(eventName, listener);
|
|
359
215
|
reject(new Error(`Event '${eventName}' not received within ${timeout}ms`));
|
|
360
216
|
}, timeout);
|
|
361
|
-
const listener = (data) => {
|
|
362
|
-
clearTimeout(timer);
|
|
363
|
-
this.removeListener(eventName, listener);
|
|
364
|
-
resolve(data);
|
|
365
|
-
};
|
|
217
|
+
const listener = (data) => { clearTimeout(timer); this.removeListener(eventName, listener); resolve(data); };
|
|
366
218
|
this.once(eventName, listener);
|
|
367
219
|
});
|
|
368
220
|
}
|
|
369
|
-
|
|
370
|
-
* Emit status change events for event-driven coordination
|
|
371
|
-
* Called by lifecycle manager when status changes
|
|
372
|
-
*/
|
|
373
|
-
emitStatusChange(newStatus) {
|
|
374
|
-
this.emit('status-changed', newStatus);
|
|
375
|
-
this.coordinator.emitEvent('agent.status-changed', {
|
|
376
|
-
agentId: this.agentId,
|
|
377
|
-
status: newStatus,
|
|
378
|
-
timestamp: Date.now()
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
/**
|
|
382
|
-
* Check if agent has a specific capability
|
|
383
|
-
*/
|
|
384
|
-
hasCapability(capabilityName) {
|
|
385
|
-
return this.capabilities.has(capabilityName);
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* Get capability details
|
|
389
|
-
*/
|
|
390
|
-
getCapability(capabilityName) {
|
|
391
|
-
return this.capabilities.get(capabilityName);
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Get all capabilities
|
|
395
|
-
*/
|
|
396
|
-
getCapabilities() {
|
|
397
|
-
return Array.from(this.capabilities.values());
|
|
398
|
-
}
|
|
399
|
-
/**
|
|
400
|
-
* Get strategies (Phase 2 B1.2)
|
|
401
|
-
* Lifecycle and memory strategies are always available (adapter or custom)
|
|
402
|
-
*/
|
|
403
|
-
getStrategies() {
|
|
404
|
-
return this.strategies;
|
|
405
|
-
}
|
|
406
|
-
/**
|
|
407
|
-
* Get the lifecycle strategy
|
|
408
|
-
*/
|
|
409
|
-
getLifecycleStrategy() {
|
|
410
|
-
return this.strategies.lifecycle;
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* Get the memory strategy
|
|
414
|
-
*/
|
|
415
|
-
getMemoryStrategy() {
|
|
416
|
-
return this.strategies.memory;
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
* Get the learning strategy (if enabled)
|
|
420
|
-
*/
|
|
421
|
-
getLearningStrategy() {
|
|
422
|
-
return this.strategies.learning;
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* Get the coordination strategy
|
|
426
|
-
*/
|
|
427
|
-
getCoordinationStrategy() {
|
|
428
|
-
return this.strategies.coordination;
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
|
-
* Register a new capability dynamically
|
|
432
|
-
*/
|
|
433
|
-
registerCapability(capability) {
|
|
434
|
-
this.capabilities.set(capability.name, capability);
|
|
435
|
-
this.emitEvent('capability.registered', {
|
|
436
|
-
agentId: this.agentId,
|
|
437
|
-
capability: capability.name
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
* Register multiple capabilities at once
|
|
442
|
-
*/
|
|
443
|
-
registerCapabilities(capabilities) {
|
|
444
|
-
for (const capability of capabilities) {
|
|
445
|
-
this.registerCapability(capability);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* Get Q-learning strategy recommendation
|
|
450
|
-
*/
|
|
221
|
+
// === Learning Interface ===
|
|
451
222
|
async recommendStrategy(taskState) {
|
|
452
223
|
if (!this.learningEngine?.isEnabled())
|
|
453
224
|
return null;
|
|
454
225
|
try {
|
|
455
226
|
return await this.learningEngine.recommendStrategy(taskState);
|
|
456
227
|
}
|
|
457
|
-
catch
|
|
458
|
-
console.error(`Strategy recommendation failed:`, error);
|
|
228
|
+
catch {
|
|
459
229
|
return null;
|
|
460
230
|
}
|
|
461
231
|
}
|
|
462
|
-
/**
|
|
463
|
-
* Get learned patterns from Q-learning
|
|
464
|
-
*/
|
|
465
232
|
async getLearnedPatterns() {
|
|
466
233
|
if (!this.learningEngine)
|
|
467
234
|
return [];
|
|
468
235
|
return await this.learningEngine.getPatterns();
|
|
469
236
|
}
|
|
470
|
-
/**
|
|
471
|
-
* Get learning engine status
|
|
472
|
-
*/
|
|
473
237
|
async getLearningStatus() {
|
|
474
238
|
if (!this.learningEngine)
|
|
475
239
|
return null;
|
|
@@ -481,51 +245,17 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
481
245
|
patterns: Array.isArray(patterns) ? patterns.length : 0
|
|
482
246
|
};
|
|
483
247
|
}
|
|
484
|
-
|
|
485
|
-
* @deprecated v2.2.0 - AgentDB is deprecated. Use SwarmMemoryManager instead.
|
|
486
|
-
* Stub method for backward compatibility - will be removed in v3.0.0.
|
|
487
|
-
*/
|
|
488
|
-
async initializeAgentDB(_config) {
|
|
489
|
-
console.warn(`[${this.agentId.id}] AgentDB is DEPRECATED and will be removed in v3.0.0`);
|
|
490
|
-
}
|
|
491
|
-
/**
|
|
492
|
-
* @deprecated v2.2.0 - Use learning strategy instead.
|
|
493
|
-
*/
|
|
494
|
-
async getAgentDBStatus() {
|
|
495
|
-
return null;
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* @deprecated v2.2.0 - Returns false, AgentDB removed.
|
|
499
|
-
*/
|
|
500
|
-
hasAgentDB() {
|
|
501
|
-
return false;
|
|
502
|
-
}
|
|
503
|
-
/**
|
|
504
|
-
* Start the agent (idempotent - safe to call multiple times)
|
|
505
|
-
*/
|
|
248
|
+
// === Start/Stop (FleetManager compatibility) ===
|
|
506
249
|
async start() {
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
if (currentStatus === types_1.AgentStatus.ACTIVE || currentStatus === types_1.AgentStatus.IDLE) {
|
|
510
|
-
console.info(`[${this.agentId.id}] Agent already started (status: ${currentStatus})`);
|
|
250
|
+
const status = this.lifecycleManager.getStatus();
|
|
251
|
+
if (status === types_1.AgentStatus.ACTIVE || status === types_1.AgentStatus.IDLE)
|
|
511
252
|
return;
|
|
512
|
-
}
|
|
513
|
-
// Otherwise, initialize the agent
|
|
514
253
|
await this.initialize();
|
|
515
254
|
}
|
|
516
|
-
|
|
517
|
-
* Stop the agent (alias for terminate)
|
|
518
|
-
* Added for FleetManager compatibility
|
|
519
|
-
*/
|
|
520
|
-
async stop() {
|
|
521
|
-
await this.terminate();
|
|
522
|
-
}
|
|
523
|
-
/**
|
|
524
|
-
* Assign a task to the agent
|
|
525
|
-
*/
|
|
255
|
+
async stop() { await this.terminate(); }
|
|
526
256
|
async assignTask(task) {
|
|
527
257
|
const assignment = {
|
|
528
|
-
id:
|
|
258
|
+
id: (0, utils_1.generateTaskId)(),
|
|
529
259
|
task,
|
|
530
260
|
agentId: this.agentId.id,
|
|
531
261
|
assignedAt: new Date(),
|
|
@@ -533,259 +263,160 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
533
263
|
};
|
|
534
264
|
await this.executeTask(assignment);
|
|
535
265
|
}
|
|
536
|
-
//
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
266
|
+
// === Deprecated (Remove in v3.0.0) ===
|
|
267
|
+
/** @deprecated v2.2.0 - AgentDB removed. Use SwarmMemoryManager. */
|
|
268
|
+
async initializeAgentDB(_config) {
|
|
269
|
+
console.warn(`[${this.agentId.id}] AgentDB is DEPRECATED`);
|
|
270
|
+
}
|
|
271
|
+
/** @deprecated v2.2.0 */
|
|
272
|
+
async getAgentDBStatus() { return null; }
|
|
273
|
+
/** @deprecated v2.2.0 */
|
|
274
|
+
hasAgentDB() { return false; }
|
|
275
|
+
// === Protected Methods ===
|
|
276
|
+
registerCapability(capability) {
|
|
277
|
+
this.capabilities.set(capability.name, capability);
|
|
278
|
+
this.emitEvent('capability.registered', { agentId: this.agentId, capability: capability.name });
|
|
279
|
+
}
|
|
280
|
+
registerCapabilities(capabilities) {
|
|
281
|
+
capabilities.forEach(cap => this.registerCapability(cap));
|
|
282
|
+
}
|
|
542
283
|
registerEventHandler(handler) {
|
|
543
284
|
this.coordinator.registerEventHandler(handler);
|
|
544
285
|
}
|
|
545
|
-
/**
|
|
546
|
-
* Emit an event
|
|
547
|
-
*/
|
|
548
286
|
emitEvent(type, data, priority = 'medium') {
|
|
549
287
|
const event = {
|
|
550
|
-
id:
|
|
551
|
-
|
|
552
|
-
source: this.agentId,
|
|
553
|
-
data,
|
|
554
|
-
timestamp: new Date(),
|
|
555
|
-
priority,
|
|
556
|
-
scope: 'global'
|
|
288
|
+
id: (0, utils_1.generateEventId)(), type, source: this.agentId, data,
|
|
289
|
+
timestamp: new Date(), priority, scope: 'global'
|
|
557
290
|
};
|
|
558
291
|
this.eventBus.emit(type, event);
|
|
559
292
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
293
|
+
emitStatusChange(newStatus) {
|
|
294
|
+
this.emit('status-changed', newStatus);
|
|
295
|
+
this.coordinator.emitEvent('agent.status-changed', { agentId: this.agentId, status: newStatus, timestamp: Date.now() });
|
|
296
|
+
}
|
|
564
297
|
async broadcastMessage(type, payload) {
|
|
565
|
-
// Use EventBus for now (AgentDB sync handles distributed state)
|
|
566
298
|
const message = {
|
|
567
|
-
id:
|
|
568
|
-
from: this.agentId,
|
|
299
|
+
id: (0, utils_1.generateMessageId)(), from: this.agentId,
|
|
569
300
|
to: { id: 'broadcast', type: 'all', created: new Date() },
|
|
570
|
-
type: type,
|
|
571
|
-
payload,
|
|
572
|
-
timestamp: new Date(),
|
|
573
|
-
priority: 'medium'
|
|
301
|
+
type: type, payload, timestamp: new Date(), priority: 'medium'
|
|
574
302
|
};
|
|
575
303
|
this.eventBus.emit('agent.message', message);
|
|
576
304
|
}
|
|
577
|
-
//
|
|
578
|
-
// Memory Operations (Phase 2 B1.2 - delegated to strategy)
|
|
579
|
-
// ============================================================================
|
|
580
|
-
/**
|
|
581
|
-
* Store data in memory with automatic namespacing
|
|
582
|
-
* Phase 2 (B1.2): Delegates to memory strategy with aqe/{agentType}/{key} namespace
|
|
583
|
-
*/
|
|
305
|
+
// === Memory Operations (delegated to strategy) ===
|
|
584
306
|
async storeMemory(key, value, ttl) {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
await memoryStrategy.storeLocal(key, value, ttl);
|
|
307
|
+
const strategy = this.strategies.memory;
|
|
308
|
+
if (strategy instanceof adapters_1.MemoryServiceAdapter) {
|
|
309
|
+
await strategy.storeLocal(key, value, ttl);
|
|
589
310
|
}
|
|
590
311
|
else {
|
|
591
|
-
|
|
592
|
-
await memoryStrategy.store(key, value, { ttl, namespace: this.agentId.type });
|
|
312
|
+
await strategy.store(key, value, { ttl, namespace: this.agentId.type });
|
|
593
313
|
}
|
|
594
314
|
}
|
|
595
|
-
/**
|
|
596
|
-
* Retrieve data from memory
|
|
597
|
-
* Phase 2 (B1.2): Delegates to memory strategy with aqe/{agentType}/{key} namespace
|
|
598
|
-
*/
|
|
599
315
|
async retrieveMemory(key) {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
return await memoryStrategy.retrieveLocal(key);
|
|
604
|
-
}
|
|
605
|
-
else {
|
|
606
|
-
// Fallback for custom strategies - must handle namespace manually
|
|
607
|
-
return await memoryStrategy.retrieve(`aqe/${this.agentId.type}/${key}`);
|
|
316
|
+
const strategy = this.strategies.memory;
|
|
317
|
+
if (strategy instanceof adapters_1.MemoryServiceAdapter) {
|
|
318
|
+
return await strategy.retrieveLocal(key);
|
|
608
319
|
}
|
|
320
|
+
return await strategy.retrieve(`aqe/${this.agentId.type}/${key}`);
|
|
609
321
|
}
|
|
610
|
-
/**
|
|
611
|
-
* Store shared data accessible by other agents
|
|
612
|
-
* Phase 2 (B1.2): Delegates to memory strategy with aqe/shared/{agentType}/{key} namespace
|
|
613
|
-
*/
|
|
614
322
|
async storeSharedMemory(key, value, ttl) {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
await memoryStrategy.storeSharedLocal(key, value, ttl);
|
|
323
|
+
const strategy = this.strategies.memory;
|
|
324
|
+
if (strategy instanceof adapters_1.MemoryServiceAdapter) {
|
|
325
|
+
await strategy.storeSharedLocal(key, value, ttl);
|
|
619
326
|
}
|
|
620
327
|
else {
|
|
621
|
-
|
|
622
|
-
await memoryStrategy.storeShared(this.agentId.type, key, value, { ttl });
|
|
328
|
+
await strategy.storeShared(this.agentId.type, key, value, { ttl });
|
|
623
329
|
}
|
|
624
330
|
}
|
|
625
|
-
/**
|
|
626
|
-
* Retrieve shared data from other agents
|
|
627
|
-
* Phase 2 (B1.2): Delegates to memory strategy with aqe/shared/{agentType}/{key} namespace
|
|
628
|
-
*/
|
|
629
331
|
async retrieveSharedMemory(agentType, key) {
|
|
630
|
-
// Phase 2 (B1.2): Use memory strategy for shared retrieval
|
|
631
332
|
return await this.strategies.memory.retrieveShared(agentType, key);
|
|
632
333
|
}
|
|
633
|
-
//
|
|
634
|
-
// Lifecycle Hooks
|
|
635
|
-
// ============================================================================
|
|
636
|
-
/**
|
|
637
|
-
* Pre-task hook - called before task execution
|
|
638
|
-
* Delegates to lifecycle strategy for pre-task processing
|
|
639
|
-
*/
|
|
334
|
+
// === Lifecycle Hooks ===
|
|
640
335
|
async onPreTask(data) {
|
|
641
336
|
this.taskStartTime = Date.now();
|
|
642
|
-
|
|
643
|
-
if (this.strategies.lifecycle.onPreTask) {
|
|
337
|
+
if (this.strategies.lifecycle.onPreTask)
|
|
644
338
|
await this.strategies.lifecycle.onPreTask(data);
|
|
339
|
+
const result = await this.hookManager.executePreTaskVerification({ task: data.assignment.task.type, context: data.context });
|
|
340
|
+
if (!result.passed) {
|
|
341
|
+
throw new Error(`Pre-task verification failed: score ${result.score}`);
|
|
645
342
|
}
|
|
646
|
-
|
|
647
|
-
const verificationResult = await this.hookManager.executePreTaskVerification({
|
|
648
|
-
task: data.assignment.task.type,
|
|
649
|
-
context: data.context
|
|
650
|
-
});
|
|
651
|
-
if (!verificationResult.passed) {
|
|
652
|
-
throw new Error(`Pre-task verification failed with score ${verificationResult.score}. ` +
|
|
653
|
-
`Checks: ${verificationResult.checks.join(', ')}`);
|
|
654
|
-
}
|
|
655
|
-
this.emitEvent('hook.pre-task.completed', {
|
|
656
|
-
agentId: this.agentId,
|
|
657
|
-
result: verificationResult
|
|
658
|
-
});
|
|
343
|
+
this.emitEvent('hook.pre-task.completed', { agentId: this.agentId, result });
|
|
659
344
|
}
|
|
660
|
-
/**
|
|
661
|
-
* Post-task hook - called after task execution
|
|
662
|
-
* Delegates to lifecycle and learning strategies
|
|
663
|
-
*/
|
|
664
345
|
async onPostTask(data) {
|
|
665
346
|
const executionTime = this.taskStartTime ? Date.now() - this.taskStartTime : 0;
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
task:
|
|
669
|
-
result: data.result
|
|
670
|
-
});
|
|
671
|
-
if (!validationResult.valid) {
|
|
672
|
-
console.warn(`Post-task validation warning with accuracy ${validationResult.accuracy}. ` +
|
|
673
|
-
`Validations: ${validationResult.validations.join(', ')}`);
|
|
347
|
+
const result = await this.hookManager.executePostTaskValidation({ task: data.assignment.task.type, result: data.result });
|
|
348
|
+
if (!result.valid) {
|
|
349
|
+
console.warn(`Post-task validation warning: accuracy ${result.accuracy}`);
|
|
674
350
|
}
|
|
675
|
-
|
|
676
|
-
if (this.strategies.lifecycle.onPostTask) {
|
|
351
|
+
if (this.strategies.lifecycle.onPostTask)
|
|
677
352
|
await this.strategies.lifecycle.onPostTask(data);
|
|
678
|
-
}
|
|
679
|
-
// Delegate learning to learning strategy (handles Q-learning, performance tracking)
|
|
680
353
|
if (this.strategies.learning?.recordExecution) {
|
|
681
354
|
await this.strategies.learning.recordExecution({
|
|
682
|
-
task: data.assignment.task,
|
|
683
|
-
result: data.result
|
|
684
|
-
success: validationResult.valid,
|
|
685
|
-
duration: executionTime,
|
|
686
|
-
metadata: {
|
|
687
|
-
taskId: data.assignment.id,
|
|
688
|
-
accuracy: validationResult.accuracy,
|
|
689
|
-
metrics: this.extractTaskMetrics(data.result)
|
|
690
|
-
}
|
|
355
|
+
task: data.assignment.task, result: data.result, success: result.valid,
|
|
356
|
+
duration: executionTime, metadata: { taskId: data.assignment.id, accuracy: result.accuracy, metrics: this.extractTaskMetrics(data.result) }
|
|
691
357
|
});
|
|
692
358
|
}
|
|
693
|
-
this.emitEvent('hook.post-task.completed', {
|
|
694
|
-
agentId: this.agentId,
|
|
695
|
-
result: validationResult
|
|
696
|
-
});
|
|
359
|
+
this.emitEvent('hook.post-task.completed', { agentId: this.agentId, result });
|
|
697
360
|
}
|
|
698
|
-
/**
|
|
699
|
-
* Task error hook - called when task execution fails
|
|
700
|
-
* Delegates to lifecycle and learning strategies
|
|
701
|
-
*/
|
|
702
361
|
async onTaskError(data) {
|
|
703
362
|
const executionTime = this.taskStartTime ? Date.now() - this.taskStartTime : 0;
|
|
704
|
-
// Store error in memory for analysis
|
|
705
363
|
await this.storeMemory(`error:${data.assignment.id}`, {
|
|
706
364
|
error: { message: data.error.message, name: data.error.name },
|
|
707
365
|
assignment: { id: data.assignment.id, taskType: data.assignment.task.type },
|
|
708
|
-
timestamp: new Date(),
|
|
709
|
-
agentId: this.agentId.id
|
|
366
|
+
timestamp: new Date(), agentId: this.agentId.id
|
|
710
367
|
});
|
|
711
|
-
|
|
712
|
-
if (this.strategies.lifecycle.onTaskError) {
|
|
368
|
+
if (this.strategies.lifecycle.onTaskError)
|
|
713
369
|
await this.strategies.lifecycle.onTaskError(data);
|
|
714
|
-
}
|
|
715
|
-
// Delegate error recording to learning strategy
|
|
716
370
|
if (this.strategies.learning?.recordExecution) {
|
|
717
371
|
await this.strategies.learning.recordExecution({
|
|
718
|
-
task: data.assignment.task,
|
|
719
|
-
|
|
720
|
-
success: false,
|
|
721
|
-
duration: executionTime,
|
|
722
|
-
metadata: {
|
|
723
|
-
taskId: data.assignment.id
|
|
724
|
-
}
|
|
372
|
+
task: data.assignment.task, error: data.error, success: false,
|
|
373
|
+
duration: executionTime, metadata: { taskId: data.assignment.id }
|
|
725
374
|
});
|
|
726
375
|
}
|
|
727
|
-
this.emitEvent('hook.task-error.completed', {
|
|
728
|
-
agentId: this.agentId,
|
|
729
|
-
error: data.error
|
|
730
|
-
}, 'high');
|
|
376
|
+
this.emitEvent('hook.task-error.completed', { agentId: this.agentId, error: data.error }, 'high');
|
|
731
377
|
}
|
|
378
|
+
// === Private Helpers ===
|
|
732
379
|
async executeHook(hookName, data) {
|
|
733
380
|
try {
|
|
734
381
|
const method = `on${hookName.charAt(0).toUpperCase()}${hookName.slice(1).replace(/-/g, '')}`;
|
|
735
|
-
if (typeof this[method] === 'function')
|
|
382
|
+
if (typeof this[method] === 'function')
|
|
736
383
|
await this[method](data);
|
|
737
|
-
}
|
|
738
384
|
}
|
|
739
385
|
catch (error) {
|
|
740
|
-
console.error(`Hook ${hookName} failed
|
|
386
|
+
console.error(`Hook ${hookName} failed:`, error);
|
|
741
387
|
}
|
|
742
388
|
}
|
|
743
|
-
// ============================================================================
|
|
744
|
-
// Helper Methods
|
|
745
|
-
// ============================================================================
|
|
746
389
|
setupEventHandlers() {
|
|
747
|
-
|
|
748
|
-
this.registerEventHandler({
|
|
749
|
-
eventType: 'fleet.shutdown',
|
|
750
|
-
handler: async () => {
|
|
751
|
-
await this.terminate();
|
|
752
|
-
}
|
|
753
|
-
});
|
|
390
|
+
this.registerEventHandler({ eventType: 'fleet.shutdown', handler: async () => { await this.terminate(); } });
|
|
754
391
|
this.registerEventHandler({
|
|
755
392
|
eventType: 'agent.ping',
|
|
756
393
|
handler: async (event) => {
|
|
757
|
-
if (event.target?.id === this.agentId.id)
|
|
394
|
+
if (event.target?.id === this.agentId.id)
|
|
758
395
|
this.emitEvent('agent.pong', { agentId: this.agentId });
|
|
759
|
-
}
|
|
760
396
|
}
|
|
761
397
|
});
|
|
762
398
|
}
|
|
763
399
|
setupLifecycleHooks() {
|
|
764
|
-
// Setup default lifecycle behavior
|
|
765
|
-
// Phase 2 (B1.2): Use lifecycle strategy for error transition
|
|
766
400
|
this.on('error', async (error) => {
|
|
767
|
-
await this.strategies.lifecycle.transitionTo(types_1.AgentStatus.ERROR, `Error
|
|
401
|
+
await this.strategies.lifecycle.transitionTo(types_1.AgentStatus.ERROR, `Error: ${error}`);
|
|
768
402
|
this.emitEvent('agent.error', { agentId: this.agentId, error });
|
|
769
403
|
});
|
|
770
404
|
}
|
|
771
405
|
validateTaskAssignment(assignment) {
|
|
772
|
-
if (!assignment
|
|
406
|
+
if (!assignment?.task)
|
|
773
407
|
throw new Error('Invalid task assignment');
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
if (!this.hasCapability(capability)) {
|
|
779
|
-
throw new Error(`Agent ${this.agentId.id} missing required capability: ${capability}`);
|
|
780
|
-
}
|
|
408
|
+
const required = assignment.task.requirements?.capabilities || [];
|
|
409
|
+
for (const cap of required) {
|
|
410
|
+
if (!this.hasCapability(cap))
|
|
411
|
+
throw new Error(`Missing capability: ${cap}`);
|
|
781
412
|
}
|
|
782
413
|
}
|
|
783
414
|
updatePerformanceMetrics(startTime, success) {
|
|
784
|
-
const
|
|
415
|
+
const time = Date.now() - startTime;
|
|
785
416
|
if (success) {
|
|
786
417
|
this.performanceMetrics.tasksCompleted++;
|
|
787
418
|
this.performanceMetrics.averageExecutionTime =
|
|
788
|
-
(this.performanceMetrics.averageExecutionTime * (this.performanceMetrics.tasksCompleted - 1) +
|
|
419
|
+
(this.performanceMetrics.averageExecutionTime * (this.performanceMetrics.tasksCompleted - 1) + time) /
|
|
789
420
|
this.performanceMetrics.tasksCompleted;
|
|
790
421
|
}
|
|
791
422
|
else {
|
|
@@ -793,47 +424,18 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
793
424
|
}
|
|
794
425
|
this.performanceMetrics.lastActivity = new Date();
|
|
795
426
|
}
|
|
796
|
-
/**
|
|
797
|
-
* Extract metrics from task result for learning
|
|
798
|
-
* Override in subclasses to provide agent-specific metrics
|
|
799
|
-
*/
|
|
800
427
|
extractTaskMetrics(result) {
|
|
801
428
|
const metrics = {};
|
|
802
|
-
// Extract common metrics if available
|
|
803
429
|
if (result && typeof result === 'object') {
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
metrics.testsGenerated = result.testsGenerated;
|
|
809
|
-
}
|
|
810
|
-
if (typeof result.issuesFound === 'number') {
|
|
811
|
-
metrics.issuesFound = result.issuesFound;
|
|
812
|
-
}
|
|
813
|
-
if (typeof result.confidenceScore === 'number') {
|
|
814
|
-
metrics.confidenceScore = result.confidenceScore;
|
|
815
|
-
}
|
|
816
|
-
if (typeof result.qualityScore === 'number') {
|
|
817
|
-
metrics.qualityScore = result.qualityScore;
|
|
818
|
-
}
|
|
430
|
+
['coverage', 'testsGenerated', 'issuesFound', 'confidenceScore', 'qualityScore'].forEach(key => {
|
|
431
|
+
if (typeof result[key] === 'number')
|
|
432
|
+
metrics[key] = result[key];
|
|
433
|
+
});
|
|
819
434
|
}
|
|
820
435
|
return metrics;
|
|
821
436
|
}
|
|
822
|
-
// State management delegated to memoryService (used in initialize/terminate)
|
|
823
437
|
async saveState() {
|
|
824
|
-
await this.memoryService.saveState({
|
|
825
|
-
performanceMetrics: this.performanceMetrics,
|
|
826
|
-
timestamp: new Date()
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
generateAgentId(type) {
|
|
830
|
-
return `${type}-${Date.now()}-${SecureRandom_js_1.SecureRandom.generateId(5)}`;
|
|
831
|
-
}
|
|
832
|
-
generateEventId() {
|
|
833
|
-
return `event-${Date.now()}-${SecureRandom_js_1.SecureRandom.generateId(5)}`;
|
|
834
|
-
}
|
|
835
|
-
generateMessageId() {
|
|
836
|
-
return `msg-${Date.now()}-${SecureRandom_js_1.SecureRandom.generateId(5)}`;
|
|
438
|
+
await this.memoryService.saveState({ performanceMetrics: this.performanceMetrics, timestamp: new Date() });
|
|
837
439
|
}
|
|
838
440
|
}
|
|
839
441
|
exports.BaseAgent = BaseAgent;
|