@compilr-dev/agents 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +1277 -0
  2. package/dist/agent.d.ts +1272 -0
  3. package/dist/agent.js +1912 -0
  4. package/dist/anchors/builtin.d.ts +24 -0
  5. package/dist/anchors/builtin.js +61 -0
  6. package/dist/anchors/index.d.ts +6 -0
  7. package/dist/anchors/index.js +5 -0
  8. package/dist/anchors/manager.d.ts +115 -0
  9. package/dist/anchors/manager.js +412 -0
  10. package/dist/anchors/types.d.ts +168 -0
  11. package/dist/anchors/types.js +10 -0
  12. package/dist/context/index.d.ts +12 -0
  13. package/dist/context/index.js +10 -0
  14. package/dist/context/manager.d.ts +224 -0
  15. package/dist/context/manager.js +770 -0
  16. package/dist/context/types.d.ts +377 -0
  17. package/dist/context/types.js +7 -0
  18. package/dist/costs/index.d.ts +8 -0
  19. package/dist/costs/index.js +7 -0
  20. package/dist/costs/tracker.d.ts +121 -0
  21. package/dist/costs/tracker.js +295 -0
  22. package/dist/costs/types.d.ts +157 -0
  23. package/dist/costs/types.js +8 -0
  24. package/dist/errors.d.ts +178 -0
  25. package/dist/errors.js +249 -0
  26. package/dist/guardrails/builtin.d.ts +27 -0
  27. package/dist/guardrails/builtin.js +223 -0
  28. package/dist/guardrails/index.d.ts +6 -0
  29. package/dist/guardrails/index.js +5 -0
  30. package/dist/guardrails/manager.d.ts +117 -0
  31. package/dist/guardrails/manager.js +288 -0
  32. package/dist/guardrails/types.d.ts +159 -0
  33. package/dist/guardrails/types.js +7 -0
  34. package/dist/hooks/index.d.ts +31 -0
  35. package/dist/hooks/index.js +29 -0
  36. package/dist/hooks/manager.d.ts +147 -0
  37. package/dist/hooks/manager.js +600 -0
  38. package/dist/hooks/types.d.ts +368 -0
  39. package/dist/hooks/types.js +12 -0
  40. package/dist/index.d.ts +45 -0
  41. package/dist/index.js +73 -0
  42. package/dist/mcp/client.d.ts +93 -0
  43. package/dist/mcp/client.js +287 -0
  44. package/dist/mcp/errors.d.ts +60 -0
  45. package/dist/mcp/errors.js +78 -0
  46. package/dist/mcp/index.d.ts +43 -0
  47. package/dist/mcp/index.js +45 -0
  48. package/dist/mcp/manager.d.ts +120 -0
  49. package/dist/mcp/manager.js +276 -0
  50. package/dist/mcp/tools.d.ts +54 -0
  51. package/dist/mcp/tools.js +99 -0
  52. package/dist/mcp/types.d.ts +150 -0
  53. package/dist/mcp/types.js +40 -0
  54. package/dist/memory/index.d.ts +8 -0
  55. package/dist/memory/index.js +7 -0
  56. package/dist/memory/loader.d.ts +114 -0
  57. package/dist/memory/loader.js +463 -0
  58. package/dist/memory/types.d.ts +182 -0
  59. package/dist/memory/types.js +8 -0
  60. package/dist/messages/index.d.ts +82 -0
  61. package/dist/messages/index.js +155 -0
  62. package/dist/permissions/index.d.ts +5 -0
  63. package/dist/permissions/index.js +4 -0
  64. package/dist/permissions/manager.d.ts +125 -0
  65. package/dist/permissions/manager.js +379 -0
  66. package/dist/permissions/types.d.ts +162 -0
  67. package/dist/permissions/types.js +7 -0
  68. package/dist/providers/claude.d.ts +90 -0
  69. package/dist/providers/claude.js +348 -0
  70. package/dist/providers/index.d.ts +8 -0
  71. package/dist/providers/index.js +11 -0
  72. package/dist/providers/mock.d.ts +133 -0
  73. package/dist/providers/mock.js +204 -0
  74. package/dist/providers/types.d.ts +168 -0
  75. package/dist/providers/types.js +4 -0
  76. package/dist/rate-limit/index.d.ts +45 -0
  77. package/dist/rate-limit/index.js +47 -0
  78. package/dist/rate-limit/limiter.d.ts +104 -0
  79. package/dist/rate-limit/limiter.js +326 -0
  80. package/dist/rate-limit/provider-wrapper.d.ts +112 -0
  81. package/dist/rate-limit/provider-wrapper.js +201 -0
  82. package/dist/rate-limit/retry.d.ts +108 -0
  83. package/dist/rate-limit/retry.js +287 -0
  84. package/dist/rate-limit/types.d.ts +181 -0
  85. package/dist/rate-limit/types.js +22 -0
  86. package/dist/rehearsal/file-analyzer.d.ts +22 -0
  87. package/dist/rehearsal/file-analyzer.js +351 -0
  88. package/dist/rehearsal/git-analyzer.d.ts +22 -0
  89. package/dist/rehearsal/git-analyzer.js +472 -0
  90. package/dist/rehearsal/index.d.ts +35 -0
  91. package/dist/rehearsal/index.js +36 -0
  92. package/dist/rehearsal/manager.d.ts +100 -0
  93. package/dist/rehearsal/manager.js +290 -0
  94. package/dist/rehearsal/types.d.ts +235 -0
  95. package/dist/rehearsal/types.js +8 -0
  96. package/dist/skills/index.d.ts +160 -0
  97. package/dist/skills/index.js +282 -0
  98. package/dist/state/agent-state.d.ts +41 -0
  99. package/dist/state/agent-state.js +88 -0
  100. package/dist/state/checkpointer.d.ts +110 -0
  101. package/dist/state/checkpointer.js +362 -0
  102. package/dist/state/errors.d.ts +66 -0
  103. package/dist/state/errors.js +88 -0
  104. package/dist/state/index.d.ts +35 -0
  105. package/dist/state/index.js +37 -0
  106. package/dist/state/serializer.d.ts +55 -0
  107. package/dist/state/serializer.js +172 -0
  108. package/dist/state/types.d.ts +312 -0
  109. package/dist/state/types.js +14 -0
  110. package/dist/tools/builtin/bash-output.d.ts +61 -0
  111. package/dist/tools/builtin/bash-output.js +90 -0
  112. package/dist/tools/builtin/bash.d.ts +150 -0
  113. package/dist/tools/builtin/bash.js +354 -0
  114. package/dist/tools/builtin/edit.d.ts +50 -0
  115. package/dist/tools/builtin/edit.js +215 -0
  116. package/dist/tools/builtin/glob.d.ts +62 -0
  117. package/dist/tools/builtin/glob.js +244 -0
  118. package/dist/tools/builtin/grep.d.ts +74 -0
  119. package/dist/tools/builtin/grep.js +363 -0
  120. package/dist/tools/builtin/index.d.ts +44 -0
  121. package/dist/tools/builtin/index.js +69 -0
  122. package/dist/tools/builtin/kill-shell.d.ts +44 -0
  123. package/dist/tools/builtin/kill-shell.js +80 -0
  124. package/dist/tools/builtin/read-file.d.ts +57 -0
  125. package/dist/tools/builtin/read-file.js +184 -0
  126. package/dist/tools/builtin/shell-manager.d.ts +176 -0
  127. package/dist/tools/builtin/shell-manager.js +337 -0
  128. package/dist/tools/builtin/task.d.ts +202 -0
  129. package/dist/tools/builtin/task.js +350 -0
  130. package/dist/tools/builtin/todo.d.ts +207 -0
  131. package/dist/tools/builtin/todo.js +453 -0
  132. package/dist/tools/builtin/utils.d.ts +27 -0
  133. package/dist/tools/builtin/utils.js +70 -0
  134. package/dist/tools/builtin/web-fetch.d.ts +96 -0
  135. package/dist/tools/builtin/web-fetch.js +290 -0
  136. package/dist/tools/builtin/write-file.d.ts +54 -0
  137. package/dist/tools/builtin/write-file.js +147 -0
  138. package/dist/tools/define.d.ts +60 -0
  139. package/dist/tools/define.js +65 -0
  140. package/dist/tools/index.d.ts +10 -0
  141. package/dist/tools/index.js +37 -0
  142. package/dist/tools/registry.d.ts +79 -0
  143. package/dist/tools/registry.js +151 -0
  144. package/dist/tools/types.d.ts +59 -0
  145. package/dist/tools/types.js +4 -0
  146. package/dist/tracing/hooks.d.ts +58 -0
  147. package/dist/tracing/hooks.js +377 -0
  148. package/dist/tracing/index.d.ts +51 -0
  149. package/dist/tracing/index.js +55 -0
  150. package/dist/tracing/logging.d.ts +78 -0
  151. package/dist/tracing/logging.js +310 -0
  152. package/dist/tracing/manager.d.ts +160 -0
  153. package/dist/tracing/manager.js +468 -0
  154. package/dist/tracing/otel.d.ts +102 -0
  155. package/dist/tracing/otel.js +246 -0
  156. package/dist/tracing/types.d.ts +346 -0
  157. package/dist/tracing/types.js +38 -0
  158. package/dist/utils/index.d.ts +23 -0
  159. package/dist/utils/index.js +44 -0
  160. package/package.json +79 -0
@@ -0,0 +1,600 @@
1
+ /**
2
+ * HooksManager - Manages lifecycle hooks for agent customization
3
+ *
4
+ * Provides:
5
+ * - Hook registration with priorities
6
+ * - Sequential execution in priority order
7
+ * - Type-safe hook invocation
8
+ * - Error handling and recovery
9
+ */
10
+ /**
11
+ * Manages lifecycle hooks for agent customization
12
+ */
13
+ export class HooksManager {
14
+ beforeIterationHooks = [];
15
+ afterIterationHooks = [];
16
+ beforeLLMHooks = [];
17
+ afterLLMHooks = [];
18
+ beforeToolHooks = [];
19
+ afterToolHooks = [];
20
+ onErrorHooks = [];
21
+ onEvent;
22
+ hookIdCounter = 0;
23
+ constructor(options = {}) {
24
+ this.onEvent = options.onEvent;
25
+ // Register initial hooks from config
26
+ if (options.hooks) {
27
+ this.registerFromConfig(options.hooks);
28
+ }
29
+ }
30
+ // ============================================================
31
+ // Registration Methods
32
+ // ============================================================
33
+ /**
34
+ * Register hooks from a configuration object
35
+ */
36
+ registerFromConfig(config) {
37
+ if (config.beforeIteration) {
38
+ for (const hook of config.beforeIteration) {
39
+ this.registerBeforeIteration(hook);
40
+ }
41
+ }
42
+ if (config.afterIteration) {
43
+ for (const hook of config.afterIteration) {
44
+ this.registerAfterIteration(hook);
45
+ }
46
+ }
47
+ if (config.beforeLLM) {
48
+ for (const hook of config.beforeLLM) {
49
+ this.registerBeforeLLM(hook);
50
+ }
51
+ }
52
+ if (config.afterLLM) {
53
+ for (const hook of config.afterLLM) {
54
+ this.registerAfterLLM(hook);
55
+ }
56
+ }
57
+ if (config.beforeTool) {
58
+ for (const hook of config.beforeTool) {
59
+ this.registerBeforeTool(hook);
60
+ }
61
+ }
62
+ if (config.afterTool) {
63
+ for (const hook of config.afterTool) {
64
+ this.registerAfterTool(hook);
65
+ }
66
+ }
67
+ if (config.onError) {
68
+ for (const hook of config.onError) {
69
+ this.registerOnError(hook);
70
+ }
71
+ }
72
+ }
73
+ /**
74
+ * Register a before:iteration hook
75
+ */
76
+ registerBeforeIteration(hook, options) {
77
+ const id = this.generateId();
78
+ this.beforeIterationHooks.push({
79
+ id,
80
+ hook,
81
+ name: options?.name,
82
+ priority: options?.priority ?? 0,
83
+ });
84
+ this.sortByPriority(this.beforeIterationHooks);
85
+ this.emitEvent({
86
+ type: 'hook:registered',
87
+ hookType: 'beforeIteration',
88
+ hookId: id,
89
+ hookName: options?.name,
90
+ });
91
+ return id;
92
+ }
93
+ /**
94
+ * Register an after:iteration hook
95
+ */
96
+ registerAfterIteration(hook, options) {
97
+ const id = this.generateId();
98
+ this.afterIterationHooks.push({
99
+ id,
100
+ hook,
101
+ name: options?.name,
102
+ priority: options?.priority ?? 0,
103
+ });
104
+ this.sortByPriority(this.afterIterationHooks);
105
+ this.emitEvent({
106
+ type: 'hook:registered',
107
+ hookType: 'afterIteration',
108
+ hookId: id,
109
+ hookName: options?.name,
110
+ });
111
+ return id;
112
+ }
113
+ /**
114
+ * Register a before:llm hook
115
+ */
116
+ registerBeforeLLM(hook, options) {
117
+ const id = this.generateId();
118
+ this.beforeLLMHooks.push({
119
+ id,
120
+ hook,
121
+ name: options?.name,
122
+ priority: options?.priority ?? 0,
123
+ });
124
+ this.sortByPriority(this.beforeLLMHooks);
125
+ this.emitEvent({
126
+ type: 'hook:registered',
127
+ hookType: 'beforeLLM',
128
+ hookId: id,
129
+ hookName: options?.name,
130
+ });
131
+ return id;
132
+ }
133
+ /**
134
+ * Register an after:llm hook
135
+ */
136
+ registerAfterLLM(hook, options) {
137
+ const id = this.generateId();
138
+ this.afterLLMHooks.push({
139
+ id,
140
+ hook,
141
+ name: options?.name,
142
+ priority: options?.priority ?? 0,
143
+ });
144
+ this.sortByPriority(this.afterLLMHooks);
145
+ this.emitEvent({
146
+ type: 'hook:registered',
147
+ hookType: 'afterLLM',
148
+ hookId: id,
149
+ hookName: options?.name,
150
+ });
151
+ return id;
152
+ }
153
+ /**
154
+ * Register a before:tool hook
155
+ */
156
+ registerBeforeTool(hook, options) {
157
+ const id = this.generateId();
158
+ this.beforeToolHooks.push({
159
+ id,
160
+ hook,
161
+ name: options?.name,
162
+ priority: options?.priority ?? 0,
163
+ });
164
+ this.sortByPriority(this.beforeToolHooks);
165
+ this.emitEvent({
166
+ type: 'hook:registered',
167
+ hookType: 'beforeTool',
168
+ hookId: id,
169
+ hookName: options?.name,
170
+ });
171
+ return id;
172
+ }
173
+ /**
174
+ * Register an after:tool hook
175
+ */
176
+ registerAfterTool(hook, options) {
177
+ const id = this.generateId();
178
+ this.afterToolHooks.push({
179
+ id,
180
+ hook,
181
+ name: options?.name,
182
+ priority: options?.priority ?? 0,
183
+ });
184
+ this.sortByPriority(this.afterToolHooks);
185
+ this.emitEvent({
186
+ type: 'hook:registered',
187
+ hookType: 'afterTool',
188
+ hookId: id,
189
+ hookName: options?.name,
190
+ });
191
+ return id;
192
+ }
193
+ /**
194
+ * Register an onError hook
195
+ */
196
+ registerOnError(hook, options) {
197
+ const id = this.generateId();
198
+ this.onErrorHooks.push({
199
+ id,
200
+ hook,
201
+ name: options?.name,
202
+ priority: options?.priority ?? 0,
203
+ });
204
+ this.sortByPriority(this.onErrorHooks);
205
+ this.emitEvent({
206
+ type: 'hook:registered',
207
+ hookType: 'onError',
208
+ hookId: id,
209
+ hookName: options?.name,
210
+ });
211
+ return id;
212
+ }
213
+ /**
214
+ * Unregister a hook by ID
215
+ */
216
+ unregister(hookId) {
217
+ const arrays = [
218
+ { arr: this.beforeIterationHooks, type: 'beforeIteration' },
219
+ { arr: this.afterIterationHooks, type: 'afterIteration' },
220
+ { arr: this.beforeLLMHooks, type: 'beforeLLM' },
221
+ { arr: this.afterLLMHooks, type: 'afterLLM' },
222
+ { arr: this.beforeToolHooks, type: 'beforeTool' },
223
+ { arr: this.afterToolHooks, type: 'afterTool' },
224
+ { arr: this.onErrorHooks, type: 'onError' },
225
+ ];
226
+ for (const { arr, type } of arrays) {
227
+ const index = arr.findIndex((h) => h.id === hookId);
228
+ if (index !== -1) {
229
+ const hook = arr[index];
230
+ arr.splice(index, 1);
231
+ this.emitEvent({ type: 'hook:unregistered', hookType: type, hookId, hookName: hook.name });
232
+ return true;
233
+ }
234
+ }
235
+ return false;
236
+ }
237
+ /**
238
+ * Clear all hooks
239
+ */
240
+ clear() {
241
+ this.beforeIterationHooks = [];
242
+ this.afterIterationHooks = [];
243
+ this.beforeLLMHooks = [];
244
+ this.afterLLMHooks = [];
245
+ this.beforeToolHooks = [];
246
+ this.afterToolHooks = [];
247
+ this.onErrorHooks = [];
248
+ }
249
+ // ============================================================
250
+ // Execution Methods
251
+ // ============================================================
252
+ /**
253
+ * Run before:iteration hooks
254
+ *
255
+ * @returns true to continue, false to skip iteration
256
+ */
257
+ async runBeforeIteration(context) {
258
+ for (const registered of this.beforeIterationHooks) {
259
+ const start = Date.now();
260
+ try {
261
+ this.emitEvent({
262
+ type: 'hook:started',
263
+ hookType: 'beforeIteration',
264
+ hookId: registered.id,
265
+ hookName: registered.name,
266
+ });
267
+ const result = await registered.hook(context);
268
+ this.emitEvent({
269
+ type: 'hook:completed',
270
+ hookType: 'beforeIteration',
271
+ hookId: registered.id,
272
+ hookName: registered.name,
273
+ durationMs: Date.now() - start,
274
+ });
275
+ if (result && typeof result === 'object' && 'skip' in result) {
276
+ return false; // Skip iteration
277
+ }
278
+ }
279
+ catch (error) {
280
+ this.emitEvent({
281
+ type: 'hook:error',
282
+ hookType: 'beforeIteration',
283
+ hookId: registered.id,
284
+ hookName: registered.name,
285
+ error: error instanceof Error ? error : new Error(String(error)),
286
+ });
287
+ // Continue with other hooks on error
288
+ }
289
+ }
290
+ return true;
291
+ }
292
+ /**
293
+ * Run after:iteration hooks
294
+ */
295
+ async runAfterIteration(context) {
296
+ for (const registered of this.afterIterationHooks) {
297
+ const start = Date.now();
298
+ try {
299
+ this.emitEvent({
300
+ type: 'hook:started',
301
+ hookType: 'afterIteration',
302
+ hookId: registered.id,
303
+ hookName: registered.name,
304
+ });
305
+ await registered.hook(context);
306
+ this.emitEvent({
307
+ type: 'hook:completed',
308
+ hookType: 'afterIteration',
309
+ hookId: registered.id,
310
+ hookName: registered.name,
311
+ durationMs: Date.now() - start,
312
+ });
313
+ }
314
+ catch (error) {
315
+ this.emitEvent({
316
+ type: 'hook:error',
317
+ hookType: 'afterIteration',
318
+ hookId: registered.id,
319
+ hookName: registered.name,
320
+ error: error instanceof Error ? error : new Error(String(error)),
321
+ });
322
+ }
323
+ }
324
+ }
325
+ /**
326
+ * Run before:llm hooks
327
+ *
328
+ * @returns potentially modified messages and tools
329
+ */
330
+ async runBeforeLLM(context) {
331
+ let messages = context.messages;
332
+ let tools = context.tools;
333
+ for (const registered of this.beforeLLMHooks) {
334
+ const start = Date.now();
335
+ try {
336
+ this.emitEvent({
337
+ type: 'hook:started',
338
+ hookType: 'beforeLLM',
339
+ hookId: registered.id,
340
+ hookName: registered.name,
341
+ });
342
+ const result = await registered.hook({ ...context, messages, tools });
343
+ this.emitEvent({
344
+ type: 'hook:completed',
345
+ hookType: 'beforeLLM',
346
+ hookId: registered.id,
347
+ hookName: registered.name,
348
+ durationMs: Date.now() - start,
349
+ });
350
+ if (result && typeof result === 'object') {
351
+ const hookResult = result;
352
+ if (hookResult.messages)
353
+ messages = hookResult.messages;
354
+ if (hookResult.tools)
355
+ tools = hookResult.tools;
356
+ }
357
+ }
358
+ catch (error) {
359
+ this.emitEvent({
360
+ type: 'hook:error',
361
+ hookType: 'beforeLLM',
362
+ hookId: registered.id,
363
+ hookName: registered.name,
364
+ error: error instanceof Error ? error : new Error(String(error)),
365
+ });
366
+ }
367
+ }
368
+ return { messages, tools };
369
+ }
370
+ /**
371
+ * Run after:llm hooks
372
+ */
373
+ async runAfterLLM(context) {
374
+ for (const registered of this.afterLLMHooks) {
375
+ const start = Date.now();
376
+ try {
377
+ this.emitEvent({
378
+ type: 'hook:started',
379
+ hookType: 'afterLLM',
380
+ hookId: registered.id,
381
+ hookName: registered.name,
382
+ });
383
+ await registered.hook(context);
384
+ this.emitEvent({
385
+ type: 'hook:completed',
386
+ hookType: 'afterLLM',
387
+ hookId: registered.id,
388
+ hookName: registered.name,
389
+ durationMs: Date.now() - start,
390
+ });
391
+ }
392
+ catch (error) {
393
+ this.emitEvent({
394
+ type: 'hook:error',
395
+ hookType: 'afterLLM',
396
+ hookId: registered.id,
397
+ hookName: registered.name,
398
+ error: error instanceof Error ? error : new Error(String(error)),
399
+ });
400
+ }
401
+ }
402
+ }
403
+ /**
404
+ * Run before:tool hooks
405
+ *
406
+ * @returns whether to proceed and potentially modified input or skip result
407
+ */
408
+ async runBeforeTool(context) {
409
+ let input = context.input;
410
+ for (const registered of this.beforeToolHooks) {
411
+ const start = Date.now();
412
+ try {
413
+ this.emitEvent({
414
+ type: 'hook:started',
415
+ hookType: 'beforeTool',
416
+ hookId: registered.id,
417
+ hookName: registered.name,
418
+ });
419
+ const result = await registered.hook({ ...context, input });
420
+ this.emitEvent({
421
+ type: 'hook:completed',
422
+ hookType: 'beforeTool',
423
+ hookId: registered.id,
424
+ hookName: registered.name,
425
+ durationMs: Date.now() - start,
426
+ });
427
+ if (result && typeof result === 'object') {
428
+ const hookResult = result;
429
+ if (hookResult.skip) {
430
+ return {
431
+ proceed: false,
432
+ input,
433
+ skipResult: hookResult.result ?? { success: false, error: 'Skipped by hook' },
434
+ };
435
+ }
436
+ if (hookResult.input)
437
+ input = hookResult.input;
438
+ }
439
+ }
440
+ catch (error) {
441
+ this.emitEvent({
442
+ type: 'hook:error',
443
+ hookType: 'beforeTool',
444
+ hookId: registered.id,
445
+ hookName: registered.name,
446
+ error: error instanceof Error ? error : new Error(String(error)),
447
+ });
448
+ }
449
+ }
450
+ return { proceed: true, input };
451
+ }
452
+ /**
453
+ * Run after:tool hooks
454
+ *
455
+ * @returns potentially modified result
456
+ */
457
+ async runAfterTool(context) {
458
+ let result = context.result;
459
+ for (const registered of this.afterToolHooks) {
460
+ const start = Date.now();
461
+ try {
462
+ this.emitEvent({
463
+ type: 'hook:started',
464
+ hookType: 'afterTool',
465
+ hookId: registered.id,
466
+ hookName: registered.name,
467
+ });
468
+ const hookReturn = await registered.hook({ ...context, result });
469
+ this.emitEvent({
470
+ type: 'hook:completed',
471
+ hookType: 'afterTool',
472
+ hookId: registered.id,
473
+ hookName: registered.name,
474
+ durationMs: Date.now() - start,
475
+ });
476
+ if (hookReturn && typeof hookReturn === 'object') {
477
+ const hookResult = hookReturn;
478
+ if (hookResult.result)
479
+ result = hookResult.result;
480
+ }
481
+ }
482
+ catch (error) {
483
+ this.emitEvent({
484
+ type: 'hook:error',
485
+ hookType: 'afterTool',
486
+ hookId: registered.id,
487
+ hookName: registered.name,
488
+ error: error instanceof Error ? error : new Error(String(error)),
489
+ });
490
+ }
491
+ }
492
+ return result;
493
+ }
494
+ /**
495
+ * Run onError hooks
496
+ *
497
+ * @returns error handling result
498
+ */
499
+ async runOnError(context) {
500
+ let finalResult = {};
501
+ for (const registered of this.onErrorHooks) {
502
+ const start = Date.now();
503
+ try {
504
+ this.emitEvent({
505
+ type: 'hook:started',
506
+ hookType: 'onError',
507
+ hookId: registered.id,
508
+ hookName: registered.name,
509
+ });
510
+ const result = await registered.hook(context);
511
+ this.emitEvent({
512
+ type: 'hook:completed',
513
+ hookType: 'onError',
514
+ hookId: registered.id,
515
+ hookName: registered.name,
516
+ durationMs: Date.now() - start,
517
+ });
518
+ if (result && typeof result === 'object') {
519
+ const hookResult = result;
520
+ if (hookResult.handled) {
521
+ finalResult = hookResult;
522
+ break; // Stop processing if error is handled
523
+ }
524
+ if (hookResult.error) {
525
+ finalResult.error = hookResult.error;
526
+ }
527
+ if (hookResult.recovery) {
528
+ finalResult.recovery = hookResult.recovery;
529
+ }
530
+ }
531
+ }
532
+ catch (hookError) {
533
+ this.emitEvent({
534
+ type: 'hook:error',
535
+ hookType: 'onError',
536
+ hookId: registered.id,
537
+ hookName: registered.name,
538
+ error: hookError instanceof Error ? hookError : new Error(String(hookError)),
539
+ });
540
+ // Continue with other error hooks
541
+ }
542
+ }
543
+ return finalResult;
544
+ }
545
+ // ============================================================
546
+ // Query Methods
547
+ // ============================================================
548
+ /**
549
+ * Check if any hooks are registered
550
+ */
551
+ hasHooks() {
552
+ return (this.beforeIterationHooks.length > 0 ||
553
+ this.afterIterationHooks.length > 0 ||
554
+ this.beforeLLMHooks.length > 0 ||
555
+ this.afterLLMHooks.length > 0 ||
556
+ this.beforeToolHooks.length > 0 ||
557
+ this.afterToolHooks.length > 0 ||
558
+ this.onErrorHooks.length > 0);
559
+ }
560
+ /**
561
+ * Get hook counts by type
562
+ */
563
+ getHookCounts() {
564
+ return {
565
+ beforeIteration: this.beforeIterationHooks.length,
566
+ afterIteration: this.afterIterationHooks.length,
567
+ beforeLLM: this.beforeLLMHooks.length,
568
+ afterLLM: this.afterLLMHooks.length,
569
+ beforeTool: this.beforeToolHooks.length,
570
+ afterTool: this.afterToolHooks.length,
571
+ onError: this.onErrorHooks.length,
572
+ };
573
+ }
574
+ /**
575
+ * Get all registered hook IDs
576
+ */
577
+ getHookIds() {
578
+ return [
579
+ ...this.beforeIterationHooks.map((h) => h.id),
580
+ ...this.afterIterationHooks.map((h) => h.id),
581
+ ...this.beforeLLMHooks.map((h) => h.id),
582
+ ...this.afterLLMHooks.map((h) => h.id),
583
+ ...this.beforeToolHooks.map((h) => h.id),
584
+ ...this.afterToolHooks.map((h) => h.id),
585
+ ...this.onErrorHooks.map((h) => h.id),
586
+ ];
587
+ }
588
+ // ============================================================
589
+ // Private Methods
590
+ // ============================================================
591
+ generateId() {
592
+ return `hook_${String(++this.hookIdCounter)}_${String(Date.now())}`;
593
+ }
594
+ sortByPriority(hooks) {
595
+ hooks.sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0));
596
+ }
597
+ emitEvent(event) {
598
+ this.onEvent?.(event);
599
+ }
600
+ }