claude-flow 2.0.0-alpha.66 → 2.0.0-alpha.67
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/cache/agent-pool.json +33 -0
- package/.claude/cache/memory-optimization.json +19 -0
- package/.claude/cache/neural-optimization.json +25 -0
- package/.claude/cache/optimized-hooks.json +19 -0
- package/.claude/cache/parallel-processing.json +26 -0
- package/.claude/optimized-settings.json +270 -0
- package/.claude/settings-enhanced.json +278 -0
- package/.claude/settings.json +105 -8
- package/CHANGELOG.md +18 -0
- package/bin/claude-flow +1 -1
- package/dist/cli/simple-commands/hive-mind.js +1 -1
- package/dist/cli/simple-commands/hive-mind.js.map +1 -1
- package/dist/cli/simple-commands/hooks.js +6 -4
- package/dist/cli/simple-commands/hooks.js.map +1 -1
- package/dist/providers/anthropic-provider.d.ts +27 -0
- package/dist/providers/anthropic-provider.d.ts.map +1 -0
- package/dist/providers/anthropic-provider.js +247 -0
- package/dist/providers/anthropic-provider.js.map +1 -0
- package/dist/providers/base-provider.d.ts +134 -0
- package/dist/providers/base-provider.d.ts.map +1 -0
- package/dist/providers/base-provider.js +407 -0
- package/dist/providers/base-provider.js.map +1 -0
- package/dist/providers/cohere-provider.d.ts +28 -0
- package/dist/providers/cohere-provider.d.ts.map +1 -0
- package/dist/providers/cohere-provider.js +407 -0
- package/dist/providers/cohere-provider.js.map +1 -0
- package/dist/providers/google-provider.d.ts +23 -0
- package/dist/providers/google-provider.d.ts.map +1 -0
- package/dist/providers/google-provider.js +362 -0
- package/dist/providers/google-provider.js.map +1 -0
- package/dist/providers/index.d.ts +14 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +18 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/ollama-provider.d.ts +23 -0
- package/dist/providers/ollama-provider.d.ts.map +1 -0
- package/dist/providers/ollama-provider.js +374 -0
- package/dist/providers/ollama-provider.js.map +1 -0
- package/dist/providers/openai-provider.d.ts +23 -0
- package/dist/providers/openai-provider.d.ts.map +1 -0
- package/dist/providers/openai-provider.js +349 -0
- package/dist/providers/openai-provider.js.map +1 -0
- package/dist/providers/provider-manager.d.ts +139 -0
- package/dist/providers/provider-manager.d.ts.map +1 -0
- package/dist/providers/provider-manager.js +513 -0
- package/dist/providers/provider-manager.js.map +1 -0
- package/dist/providers/types.d.ts +356 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +61 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/providers/utils.d.ts +37 -0
- package/dist/providers/utils.d.ts.map +1 -0
- package/dist/providers/utils.js +322 -0
- package/dist/providers/utils.js.map +1 -0
- package/dist/services/agentic-flow-hooks/hook-manager.d.ts +70 -0
- package/dist/services/agentic-flow-hooks/hook-manager.d.ts.map +1 -0
- package/dist/services/agentic-flow-hooks/hook-manager.js +512 -0
- package/dist/services/agentic-flow-hooks/hook-manager.js.map +1 -0
- package/dist/services/agentic-flow-hooks/index.d.ts +36 -0
- package/dist/services/agentic-flow-hooks/index.d.ts.map +1 -0
- package/dist/services/agentic-flow-hooks/index.js +325 -0
- package/dist/services/agentic-flow-hooks/index.js.map +1 -0
- package/dist/services/agentic-flow-hooks/llm-hooks.d.ts +33 -0
- package/dist/services/agentic-flow-hooks/llm-hooks.d.ts.map +1 -0
- package/dist/services/agentic-flow-hooks/llm-hooks.js +415 -0
- package/dist/services/agentic-flow-hooks/llm-hooks.js.map +1 -0
- package/dist/services/agentic-flow-hooks/memory-hooks.d.ts +45 -0
- package/dist/services/agentic-flow-hooks/memory-hooks.d.ts.map +1 -0
- package/dist/services/agentic-flow-hooks/memory-hooks.js +532 -0
- package/dist/services/agentic-flow-hooks/memory-hooks.js.map +1 -0
- package/dist/services/agentic-flow-hooks/neural-hooks.d.ts +39 -0
- package/dist/services/agentic-flow-hooks/neural-hooks.d.ts.map +1 -0
- package/dist/services/agentic-flow-hooks/neural-hooks.js +561 -0
- package/dist/services/agentic-flow-hooks/neural-hooks.js.map +1 -0
- package/dist/services/agentic-flow-hooks/performance-hooks.d.ts +33 -0
- package/dist/services/agentic-flow-hooks/performance-hooks.d.ts.map +1 -0
- package/dist/services/agentic-flow-hooks/performance-hooks.js +621 -0
- package/dist/services/agentic-flow-hooks/performance-hooks.js.map +1 -0
- package/dist/services/agentic-flow-hooks/types.d.ts +379 -0
- package/dist/services/agentic-flow-hooks/types.d.ts.map +1 -0
- package/dist/services/agentic-flow-hooks/types.js +8 -0
- package/dist/services/agentic-flow-hooks/types.js.map +1 -0
- package/dist/services/agentic-flow-hooks/workflow-hooks.d.ts +39 -0
- package/dist/services/agentic-flow-hooks/workflow-hooks.d.ts.map +1 -0
- package/dist/services/agentic-flow-hooks/workflow-hooks.js +742 -0
- package/dist/services/agentic-flow-hooks/workflow-hooks.js.map +1 -0
- package/package.json +1 -1
- package/scripts/optimize-performance.js +400 -0
- package/scripts/performance-monitor.js +263 -0
- package/src/cli/help-text.js +1 -1
- package/src/cli/simple-cli.js +1 -1
- package/src/cli/simple-commands/hive-mind.js +1 -1
- package/src/providers/anthropic-provider.ts +282 -0
- package/src/providers/base-provider.ts +560 -0
- package/src/providers/cohere-provider.ts +521 -0
- package/src/providers/google-provider.ts +477 -0
- package/src/providers/index.ts +21 -0
- package/src/providers/ollama-provider.ts +489 -0
- package/src/providers/openai-provider.ts +476 -0
- package/src/providers/provider-manager.ts +654 -0
- package/src/providers/types.ts +531 -0
- package/src/providers/utils.ts +376 -0
- package/src/services/agentic-flow-hooks/hook-manager.ts +701 -0
- package/src/services/agentic-flow-hooks/index.ts +386 -0
- package/src/services/agentic-flow-hooks/llm-hooks.ts +557 -0
- package/src/services/agentic-flow-hooks/memory-hooks.ts +710 -0
- package/src/services/agentic-flow-hooks/neural-hooks.ts +758 -0
- package/src/services/agentic-flow-hooks/performance-hooks.ts +827 -0
- package/src/services/agentic-flow-hooks/types.ts +503 -0
- package/src/services/agentic-flow-hooks/workflow-hooks.ts +1026 -0
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agentic Flow Hook Manager
|
|
3
|
+
*
|
|
4
|
+
* Central manager for all agentic-flow hooks, providing registration,
|
|
5
|
+
* execution, and lifecycle management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { EventEmitter } from 'events';
|
|
9
|
+
import { Logger } from '../../core/logger.js';
|
|
10
|
+
import type {
|
|
11
|
+
AgenticHookContext,
|
|
12
|
+
AgenticHookType,
|
|
13
|
+
HookFilter,
|
|
14
|
+
HookHandler,
|
|
15
|
+
HookHandlerResult,
|
|
16
|
+
HookOptions,
|
|
17
|
+
HookPayload,
|
|
18
|
+
HookPipeline,
|
|
19
|
+
HookRegistration,
|
|
20
|
+
HookRegistry,
|
|
21
|
+
PipelineMetrics,
|
|
22
|
+
PipelineStage,
|
|
23
|
+
SideEffect,
|
|
24
|
+
} from './types.js';
|
|
25
|
+
|
|
26
|
+
const logger = new Logger({
|
|
27
|
+
level: 'info',
|
|
28
|
+
format: 'text',
|
|
29
|
+
destination: 'console'
|
|
30
|
+
}, { prefix: 'AgenticHookManager' });
|
|
31
|
+
|
|
32
|
+
export class AgenticHookManager extends EventEmitter implements HookRegistry {
|
|
33
|
+
private hooks: Map<AgenticHookType, HookRegistration[]> = new Map();
|
|
34
|
+
private pipelines: Map<string, HookPipeline> = new Map();
|
|
35
|
+
private metrics: Map<string, any> = new Map();
|
|
36
|
+
private activeExecutions: Set<string> = new Set();
|
|
37
|
+
|
|
38
|
+
constructor() {
|
|
39
|
+
super();
|
|
40
|
+
this.initializeMetrics();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Register a new hook
|
|
45
|
+
*/
|
|
46
|
+
register(registration: HookRegistration): void {
|
|
47
|
+
const { type, id } = registration;
|
|
48
|
+
|
|
49
|
+
// Validate registration
|
|
50
|
+
this.validateRegistration(registration);
|
|
51
|
+
|
|
52
|
+
// Get or create hook list for type
|
|
53
|
+
if (!this.hooks.has(type)) {
|
|
54
|
+
this.hooks.set(type, []);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const hookList = this.hooks.get(type)!;
|
|
58
|
+
|
|
59
|
+
// Check for duplicate ID
|
|
60
|
+
if (hookList.some(h => h.id === id)) {
|
|
61
|
+
throw new Error(`Hook with ID '${id}' already registered for type '${type}'`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Insert hook sorted by priority (higher priority first)
|
|
65
|
+
const insertIndex = hookList.findIndex(h => h.priority < registration.priority);
|
|
66
|
+
if (insertIndex === -1) {
|
|
67
|
+
hookList.push(registration);
|
|
68
|
+
} else {
|
|
69
|
+
hookList.splice(insertIndex, 0, registration);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
logger.info(`Registered hook '${id}' for type '${type}' with priority ${registration.priority}`);
|
|
73
|
+
this.emit('hook:registered', { type, registration });
|
|
74
|
+
|
|
75
|
+
// Update metrics
|
|
76
|
+
this.updateMetric('hooks.registered', 1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Unregister a hook
|
|
81
|
+
*/
|
|
82
|
+
unregister(id: string): void {
|
|
83
|
+
let found = false;
|
|
84
|
+
|
|
85
|
+
for (const [type, hookList] of this.hooks.entries()) {
|
|
86
|
+
const index = hookList.findIndex(h => h.id === id);
|
|
87
|
+
if (index !== -1) {
|
|
88
|
+
hookList.splice(index, 1);
|
|
89
|
+
found = true;
|
|
90
|
+
|
|
91
|
+
logger.info(`Unregistered hook '${id}' from type '${type}'`);
|
|
92
|
+
this.emit('hook:unregistered', { type, id });
|
|
93
|
+
|
|
94
|
+
// Clean up empty lists
|
|
95
|
+
if (hookList.length === 0) {
|
|
96
|
+
this.hooks.delete(type);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!found) {
|
|
104
|
+
throw new Error(`Hook with ID '${id}' not found`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.updateMetric('hooks.unregistered', 1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get hooks by type with optional filtering
|
|
112
|
+
*/
|
|
113
|
+
getHooks(type: AgenticHookType, filter?: HookFilter): HookRegistration[] {
|
|
114
|
+
const hookList = this.hooks.get(type) || [];
|
|
115
|
+
|
|
116
|
+
if (!filter) {
|
|
117
|
+
return [...hookList];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return hookList.filter(hook => this.matchesFilter(hook, filter));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Execute hooks for a given type
|
|
125
|
+
*/
|
|
126
|
+
async executeHooks(
|
|
127
|
+
type: AgenticHookType,
|
|
128
|
+
payload: HookPayload,
|
|
129
|
+
context: AgenticHookContext
|
|
130
|
+
): Promise<HookHandlerResult[]> {
|
|
131
|
+
const executionId = this.generateExecutionId();
|
|
132
|
+
this.activeExecutions.add(executionId);
|
|
133
|
+
|
|
134
|
+
const startTime = Date.now();
|
|
135
|
+
const results: HookHandlerResult[] = [];
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
// Get applicable hooks
|
|
139
|
+
const hooks = this.getHooks(type, this.createFilterFromPayload(payload));
|
|
140
|
+
|
|
141
|
+
logger.debug(`Executing ${hooks.length} hooks for type '${type}'`);
|
|
142
|
+
this.emit('hooks:executing', { type, count: hooks.length, executionId });
|
|
143
|
+
|
|
144
|
+
// Execute hooks in order
|
|
145
|
+
let modifiedPayload = payload;
|
|
146
|
+
for (const hook of hooks) {
|
|
147
|
+
try {
|
|
148
|
+
const result = await this.executeHook(hook, modifiedPayload, context);
|
|
149
|
+
results.push(result);
|
|
150
|
+
|
|
151
|
+
// Handle side effects
|
|
152
|
+
if (result.sideEffects) {
|
|
153
|
+
await this.processSideEffects(result.sideEffects, context);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Update payload if modified
|
|
157
|
+
if (result.modified && result.payload) {
|
|
158
|
+
modifiedPayload = result.payload;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Check if we should continue
|
|
162
|
+
if (!result.continue) {
|
|
163
|
+
logger.debug(`Hook '${hook.id}' halted execution chain`);
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
await this.handleHookError(hook, error as Error, context);
|
|
168
|
+
|
|
169
|
+
// Determine if we should continue after error
|
|
170
|
+
if (hook.options?.errorHandler) {
|
|
171
|
+
hook.options.errorHandler(error as Error);
|
|
172
|
+
} else {
|
|
173
|
+
throw error; // Re-throw if no error handler
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Update metrics
|
|
179
|
+
const duration = Date.now() - startTime;
|
|
180
|
+
this.updateMetric('hooks.executions', 1);
|
|
181
|
+
this.updateMetric('hooks.totalDuration', duration);
|
|
182
|
+
this.updateMetric(`hooks.${type}.executions`, 1);
|
|
183
|
+
this.updateMetric(`hooks.${type}.duration`, duration);
|
|
184
|
+
|
|
185
|
+
this.emit('hooks:executed', {
|
|
186
|
+
type,
|
|
187
|
+
results,
|
|
188
|
+
duration,
|
|
189
|
+
executionId
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return results;
|
|
193
|
+
} finally {
|
|
194
|
+
this.activeExecutions.delete(executionId);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Create a new hook pipeline
|
|
200
|
+
*/
|
|
201
|
+
createPipeline(config: Partial<HookPipeline>): HookPipeline {
|
|
202
|
+
const pipeline: HookPipeline = {
|
|
203
|
+
id: config.id || this.generatePipelineId(),
|
|
204
|
+
name: config.name || 'Unnamed Pipeline',
|
|
205
|
+
stages: config.stages || [],
|
|
206
|
+
errorStrategy: config.errorStrategy || 'fail-fast',
|
|
207
|
+
metrics: {
|
|
208
|
+
executions: 0,
|
|
209
|
+
avgDuration: 0,
|
|
210
|
+
errorRate: 0,
|
|
211
|
+
throughput: 0,
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
this.pipelines.set(pipeline.id, pipeline);
|
|
216
|
+
logger.info(`Created pipeline '${pipeline.name}' with ID '${pipeline.id}'`);
|
|
217
|
+
|
|
218
|
+
return pipeline;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Execute a pipeline
|
|
223
|
+
*/
|
|
224
|
+
async executePipeline(
|
|
225
|
+
pipelineId: string,
|
|
226
|
+
initialPayload: HookPayload,
|
|
227
|
+
context: AgenticHookContext
|
|
228
|
+
): Promise<HookHandlerResult[]> {
|
|
229
|
+
const pipeline = this.pipelines.get(pipelineId);
|
|
230
|
+
if (!pipeline) {
|
|
231
|
+
throw new Error(`Pipeline '${pipelineId}' not found`);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const startTime = Date.now();
|
|
235
|
+
const results: HookHandlerResult[] = [];
|
|
236
|
+
let currentPayload = initialPayload;
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
for (const stage of pipeline.stages) {
|
|
240
|
+
// Check stage condition
|
|
241
|
+
if (stage.condition && !stage.condition(context)) {
|
|
242
|
+
logger.debug(`Skipping stage '${stage.name}' due to condition`);
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Execute stage hooks
|
|
247
|
+
const stageResults = await this.executeStage(
|
|
248
|
+
stage,
|
|
249
|
+
currentPayload,
|
|
250
|
+
context
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
// Apply stage transform if provided
|
|
254
|
+
if (stage.transform) {
|
|
255
|
+
for (let i = 0; i < stageResults.length; i++) {
|
|
256
|
+
stageResults[i] = stage.transform(stageResults[i]);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
results.push(...stageResults);
|
|
261
|
+
|
|
262
|
+
// Update payload for next stage
|
|
263
|
+
const lastModified = stageResults
|
|
264
|
+
.reverse()
|
|
265
|
+
.find(r => r.modified && r.payload);
|
|
266
|
+
if (lastModified) {
|
|
267
|
+
currentPayload = lastModified.payload;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Update pipeline metrics
|
|
272
|
+
this.updatePipelineMetrics(pipeline, Date.now() - startTime, false);
|
|
273
|
+
|
|
274
|
+
return results;
|
|
275
|
+
} catch (error) {
|
|
276
|
+
// Update error metrics
|
|
277
|
+
this.updatePipelineMetrics(pipeline, Date.now() - startTime, true);
|
|
278
|
+
|
|
279
|
+
// Handle error based on strategy
|
|
280
|
+
if (pipeline.errorStrategy === 'rollback') {
|
|
281
|
+
await this.rollbackPipeline(pipeline, results, context);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Get current metrics
|
|
290
|
+
*/
|
|
291
|
+
getMetrics(): Record<string, any> {
|
|
292
|
+
const metrics: Record<string, any> = {};
|
|
293
|
+
|
|
294
|
+
for (const [key, value] of this.metrics.entries()) {
|
|
295
|
+
metrics[key] = value;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Add computed metrics
|
|
299
|
+
metrics['hooks.count'] = this.getTotalHookCount();
|
|
300
|
+
metrics['hooks.types'] = Array.from(this.hooks.keys());
|
|
301
|
+
metrics['pipelines.count'] = this.pipelines.size;
|
|
302
|
+
metrics['executions.active'] = this.activeExecutions.size;
|
|
303
|
+
|
|
304
|
+
return metrics;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ===== Private Methods =====
|
|
308
|
+
|
|
309
|
+
private validateRegistration(registration: HookRegistration): void {
|
|
310
|
+
if (!registration.id) {
|
|
311
|
+
throw new Error('Hook registration must have an ID');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!registration.type) {
|
|
315
|
+
throw new Error('Hook registration must have a type');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (typeof registration.handler !== 'function') {
|
|
319
|
+
throw new Error('Hook registration must have a handler function');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (registration.priority < 0) {
|
|
323
|
+
throw new Error('Hook priority must be non-negative');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private matchesFilter(hook: HookRegistration, filter: HookFilter): boolean {
|
|
328
|
+
if (!hook.filter) {
|
|
329
|
+
return true; // No filter means hook applies to all
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Check providers
|
|
333
|
+
if (filter.providers && hook.filter.providers) {
|
|
334
|
+
const hasProvider = filter.providers.some(p =>
|
|
335
|
+
hook.filter!.providers!.includes(p)
|
|
336
|
+
);
|
|
337
|
+
if (!hasProvider) return false;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Check models
|
|
341
|
+
if (filter.models && hook.filter.models) {
|
|
342
|
+
const hasModel = filter.models.some(m =>
|
|
343
|
+
hook.filter!.models!.includes(m)
|
|
344
|
+
);
|
|
345
|
+
if (!hasModel) return false;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Check patterns
|
|
349
|
+
if (filter.patterns && hook.filter.patterns) {
|
|
350
|
+
// Complex pattern matching logic here
|
|
351
|
+
// For now, simplified version
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Check conditions
|
|
356
|
+
if (filter.conditions && hook.filter.conditions) {
|
|
357
|
+
// Evaluate conditions
|
|
358
|
+
// Simplified for now
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
private createFilterFromPayload(payload: HookPayload): HookFilter | undefined {
|
|
366
|
+
const filter: HookFilter = {};
|
|
367
|
+
|
|
368
|
+
// Extract filter criteria from payload
|
|
369
|
+
if ('provider' in payload) {
|
|
370
|
+
filter.providers = [payload.provider];
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if ('model' in payload) {
|
|
374
|
+
filter.models = [payload.model];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if ('operation' in payload) {
|
|
378
|
+
filter.operations = [payload.operation];
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if ('namespace' in payload) {
|
|
382
|
+
filter.namespaces = [payload.namespace];
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return Object.keys(filter).length > 0 ? filter : undefined;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
private async executeHook(
|
|
389
|
+
hook: HookRegistration,
|
|
390
|
+
payload: HookPayload,
|
|
391
|
+
context: AgenticHookContext
|
|
392
|
+
): Promise<HookHandlerResult> {
|
|
393
|
+
const startTime = Date.now();
|
|
394
|
+
|
|
395
|
+
try {
|
|
396
|
+
// Check cache if enabled
|
|
397
|
+
if (hook.options?.cache?.enabled) {
|
|
398
|
+
const cacheKey = hook.options.cache.key(payload);
|
|
399
|
+
const cached = this.getCachedResult(hook.id, cacheKey);
|
|
400
|
+
if (cached) {
|
|
401
|
+
this.updateMetric('hooks.cacheHits', 1);
|
|
402
|
+
return cached;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Execute with timeout if specified
|
|
407
|
+
let resultPromise = hook.handler(payload, context);
|
|
408
|
+
|
|
409
|
+
if (hook.options?.timeout) {
|
|
410
|
+
resultPromise = this.withTimeout(
|
|
411
|
+
resultPromise,
|
|
412
|
+
hook.options.timeout,
|
|
413
|
+
`Hook '${hook.id}' timed out`
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const result = await resultPromise;
|
|
418
|
+
|
|
419
|
+
// Cache result if enabled
|
|
420
|
+
if (hook.options?.cache?.enabled && result) {
|
|
421
|
+
const cacheKey = hook.options.cache.key(payload);
|
|
422
|
+
this.cacheResult(hook.id, cacheKey, result, hook.options.cache.ttl);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Update hook-specific metrics
|
|
426
|
+
const duration = Date.now() - startTime;
|
|
427
|
+
this.updateMetric(`hooks.${hook.id}.executions`, 1);
|
|
428
|
+
this.updateMetric(`hooks.${hook.id}.duration`, duration);
|
|
429
|
+
|
|
430
|
+
return result;
|
|
431
|
+
} catch (error) {
|
|
432
|
+
// Handle retries if configured
|
|
433
|
+
if (hook.options?.retries && hook.options.retries > 0) {
|
|
434
|
+
logger.warn(`Hook '${hook.id}' failed, retrying...`);
|
|
435
|
+
return this.retryHook(hook, payload, context, hook.options.retries);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Use fallback if provided
|
|
439
|
+
if (hook.options?.fallback) {
|
|
440
|
+
logger.warn(`Hook '${hook.id}' failed, using fallback`);
|
|
441
|
+
return hook.options.fallback(payload, context);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
throw error;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
private async retryHook(
|
|
449
|
+
hook: HookRegistration,
|
|
450
|
+
payload: HookPayload,
|
|
451
|
+
context: AgenticHookContext,
|
|
452
|
+
retriesLeft: number
|
|
453
|
+
): Promise<HookHandlerResult> {
|
|
454
|
+
for (let i = 0; i < retriesLeft; i++) {
|
|
455
|
+
try {
|
|
456
|
+
await this.delay(Math.pow(2, i) * 1000); // Exponential backoff
|
|
457
|
+
return await hook.handler(payload, context);
|
|
458
|
+
} catch (error) {
|
|
459
|
+
if (i === retriesLeft - 1) {
|
|
460
|
+
throw error; // Last retry failed
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Should not reach here
|
|
466
|
+
throw new Error('Retry logic error');
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
private async processSideEffects(
|
|
470
|
+
sideEffects: SideEffect[],
|
|
471
|
+
context: AgenticHookContext
|
|
472
|
+
): Promise<void> {
|
|
473
|
+
for (const effect of sideEffects) {
|
|
474
|
+
try {
|
|
475
|
+
await this.processSideEffect(effect, context);
|
|
476
|
+
} catch (error) {
|
|
477
|
+
logger.error(`Failed to process side effect: ${effect.type}`, error);
|
|
478
|
+
// Continue processing other side effects
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
private async processSideEffect(
|
|
484
|
+
effect: SideEffect,
|
|
485
|
+
context: AgenticHookContext
|
|
486
|
+
): Promise<void> {
|
|
487
|
+
switch (effect.type) {
|
|
488
|
+
case 'memory':
|
|
489
|
+
await this.processMemorySideEffect(effect, context);
|
|
490
|
+
break;
|
|
491
|
+
|
|
492
|
+
case 'neural':
|
|
493
|
+
await this.processNeuralSideEffect(effect, context);
|
|
494
|
+
break;
|
|
495
|
+
|
|
496
|
+
case 'metric':
|
|
497
|
+
this.processMetricSideEffect(effect);
|
|
498
|
+
break;
|
|
499
|
+
|
|
500
|
+
case 'notification':
|
|
501
|
+
this.processNotificationSideEffect(effect);
|
|
502
|
+
break;
|
|
503
|
+
|
|
504
|
+
case 'log':
|
|
505
|
+
this.processLogSideEffect(effect);
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
private async processMemorySideEffect(
|
|
511
|
+
effect: SideEffect,
|
|
512
|
+
context: AgenticHookContext
|
|
513
|
+
): Promise<void> {
|
|
514
|
+
// Implement memory side effect processing
|
|
515
|
+
// This would integrate with the memory service
|
|
516
|
+
logger.debug(`Processing memory side effect: ${effect.action}`, effect.data);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
private async processNeuralSideEffect(
|
|
520
|
+
effect: SideEffect,
|
|
521
|
+
context: AgenticHookContext
|
|
522
|
+
): Promise<void> {
|
|
523
|
+
// Implement neural side effect processing
|
|
524
|
+
// This would integrate with the neural service
|
|
525
|
+
logger.debug(`Processing neural side effect: ${effect.action}`, effect.data);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
private processMetricSideEffect(effect: SideEffect): void {
|
|
529
|
+
if (effect.action === 'update') {
|
|
530
|
+
this.updateMetric(effect.data.name, effect.data.value);
|
|
531
|
+
} else if (effect.action === 'increment') {
|
|
532
|
+
this.updateMetric(effect.data.name, 1);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
private processNotificationSideEffect(effect: SideEffect): void {
|
|
537
|
+
this.emit('notification', effect.data);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
private processLogSideEffect(effect: SideEffect): void {
|
|
541
|
+
const { level = 'info', message, data } = effect.data;
|
|
542
|
+
logger[level as keyof Logger](message, data);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
private async handleHookError(
|
|
546
|
+
hook: HookRegistration,
|
|
547
|
+
error: Error,
|
|
548
|
+
context: AgenticHookContext
|
|
549
|
+
): Promise<void> {
|
|
550
|
+
logger.error(`Hook '${hook.id}' error:`, error);
|
|
551
|
+
|
|
552
|
+
this.updateMetric('hooks.errors', 1);
|
|
553
|
+
this.updateMetric(`hooks.${hook.id}.errors`, 1);
|
|
554
|
+
|
|
555
|
+
this.emit('hook:error', {
|
|
556
|
+
hookId: hook.id,
|
|
557
|
+
type: hook.type,
|
|
558
|
+
error,
|
|
559
|
+
context,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
private async executeStage(
|
|
564
|
+
stage: PipelineStage,
|
|
565
|
+
payload: HookPayload,
|
|
566
|
+
context: AgenticHookContext
|
|
567
|
+
): Promise<HookHandlerResult[]> {
|
|
568
|
+
if (stage.parallel) {
|
|
569
|
+
// Execute hooks in parallel
|
|
570
|
+
const promises = stage.hooks.map(hook =>
|
|
571
|
+
this.executeHook(hook, payload, context)
|
|
572
|
+
);
|
|
573
|
+
return Promise.all(promises);
|
|
574
|
+
} else {
|
|
575
|
+
// Execute hooks sequentially
|
|
576
|
+
const results: HookHandlerResult[] = [];
|
|
577
|
+
let currentPayload = payload;
|
|
578
|
+
|
|
579
|
+
for (const hook of stage.hooks) {
|
|
580
|
+
const result = await this.executeHook(hook, currentPayload, context);
|
|
581
|
+
results.push(result);
|
|
582
|
+
|
|
583
|
+
if (result.modified && result.payload) {
|
|
584
|
+
currentPayload = result.payload;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (!result.continue) {
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
return results;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
private updatePipelineMetrics(
|
|
597
|
+
pipeline: HookPipeline,
|
|
598
|
+
duration: number,
|
|
599
|
+
hasError: boolean
|
|
600
|
+
): void {
|
|
601
|
+
const metrics = pipeline.metrics;
|
|
602
|
+
|
|
603
|
+
metrics.executions++;
|
|
604
|
+
metrics.avgDuration =
|
|
605
|
+
(metrics.avgDuration * (metrics.executions - 1) + duration) /
|
|
606
|
+
metrics.executions;
|
|
607
|
+
|
|
608
|
+
if (hasError) {
|
|
609
|
+
metrics.errorRate =
|
|
610
|
+
(metrics.errorRate * (metrics.executions - 1) + 1) /
|
|
611
|
+
metrics.executions;
|
|
612
|
+
} else {
|
|
613
|
+
metrics.errorRate =
|
|
614
|
+
(metrics.errorRate * (metrics.executions - 1)) /
|
|
615
|
+
metrics.executions;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// Calculate throughput (executions per minute)
|
|
619
|
+
const timeWindow = 60000; // 1 minute
|
|
620
|
+
metrics.throughput = (metrics.executions / duration) * timeWindow;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
private async rollbackPipeline(
|
|
624
|
+
pipeline: HookPipeline,
|
|
625
|
+
results: HookHandlerResult[],
|
|
626
|
+
context: AgenticHookContext
|
|
627
|
+
): Promise<void> {
|
|
628
|
+
logger.warn(`Rolling back pipeline '${pipeline.name}'`);
|
|
629
|
+
// Implement rollback logic based on side effects in results
|
|
630
|
+
// This is a placeholder for actual rollback implementation
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
private getTotalHookCount(): number {
|
|
634
|
+
let count = 0;
|
|
635
|
+
for (const hookList of this.hooks.values()) {
|
|
636
|
+
count += hookList.length;
|
|
637
|
+
}
|
|
638
|
+
return count;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
private initializeMetrics(): void {
|
|
642
|
+
this.metrics.set('hooks.registered', 0);
|
|
643
|
+
this.metrics.set('hooks.unregistered', 0);
|
|
644
|
+
this.metrics.set('hooks.executions', 0);
|
|
645
|
+
this.metrics.set('hooks.errors', 0);
|
|
646
|
+
this.metrics.set('hooks.cacheHits', 0);
|
|
647
|
+
this.metrics.set('hooks.totalDuration', 0);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
private updateMetric(key: string, value: number): void {
|
|
651
|
+
const current = this.metrics.get(key) || 0;
|
|
652
|
+
this.metrics.set(key, current + value);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
private generateExecutionId(): string {
|
|
656
|
+
return `exec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
private generatePipelineId(): string {
|
|
660
|
+
return `pipe_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
private getCachedResult(
|
|
664
|
+
hookId: string,
|
|
665
|
+
cacheKey: string
|
|
666
|
+
): HookHandlerResult | null {
|
|
667
|
+
// Implement cache retrieval
|
|
668
|
+
// This is a placeholder
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
private cacheResult(
|
|
673
|
+
hookId: string,
|
|
674
|
+
cacheKey: string,
|
|
675
|
+
result: HookHandlerResult,
|
|
676
|
+
ttl: number
|
|
677
|
+
): void {
|
|
678
|
+
// Implement cache storage
|
|
679
|
+
// This is a placeholder
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
private async withTimeout<T>(
|
|
683
|
+
promise: Promise<T>,
|
|
684
|
+
timeout: number,
|
|
685
|
+
message: string
|
|
686
|
+
): Promise<T> {
|
|
687
|
+
return Promise.race([
|
|
688
|
+
promise,
|
|
689
|
+
new Promise<T>((_, reject) =>
|
|
690
|
+
setTimeout(() => reject(new Error(message)), timeout)
|
|
691
|
+
),
|
|
692
|
+
]);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
private delay(ms: number): Promise<void> {
|
|
696
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Export singleton instance
|
|
701
|
+
export const agenticHookManager = new AgenticHookManager();
|