@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.
- package/README.md +1277 -0
- package/dist/agent.d.ts +1272 -0
- package/dist/agent.js +1912 -0
- package/dist/anchors/builtin.d.ts +24 -0
- package/dist/anchors/builtin.js +61 -0
- package/dist/anchors/index.d.ts +6 -0
- package/dist/anchors/index.js +5 -0
- package/dist/anchors/manager.d.ts +115 -0
- package/dist/anchors/manager.js +412 -0
- package/dist/anchors/types.d.ts +168 -0
- package/dist/anchors/types.js +10 -0
- package/dist/context/index.d.ts +12 -0
- package/dist/context/index.js +10 -0
- package/dist/context/manager.d.ts +224 -0
- package/dist/context/manager.js +770 -0
- package/dist/context/types.d.ts +377 -0
- package/dist/context/types.js +7 -0
- package/dist/costs/index.d.ts +8 -0
- package/dist/costs/index.js +7 -0
- package/dist/costs/tracker.d.ts +121 -0
- package/dist/costs/tracker.js +295 -0
- package/dist/costs/types.d.ts +157 -0
- package/dist/costs/types.js +8 -0
- package/dist/errors.d.ts +178 -0
- package/dist/errors.js +249 -0
- package/dist/guardrails/builtin.d.ts +27 -0
- package/dist/guardrails/builtin.js +223 -0
- package/dist/guardrails/index.d.ts +6 -0
- package/dist/guardrails/index.js +5 -0
- package/dist/guardrails/manager.d.ts +117 -0
- package/dist/guardrails/manager.js +288 -0
- package/dist/guardrails/types.d.ts +159 -0
- package/dist/guardrails/types.js +7 -0
- package/dist/hooks/index.d.ts +31 -0
- package/dist/hooks/index.js +29 -0
- package/dist/hooks/manager.d.ts +147 -0
- package/dist/hooks/manager.js +600 -0
- package/dist/hooks/types.d.ts +368 -0
- package/dist/hooks/types.js +12 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +73 -0
- package/dist/mcp/client.d.ts +93 -0
- package/dist/mcp/client.js +287 -0
- package/dist/mcp/errors.d.ts +60 -0
- package/dist/mcp/errors.js +78 -0
- package/dist/mcp/index.d.ts +43 -0
- package/dist/mcp/index.js +45 -0
- package/dist/mcp/manager.d.ts +120 -0
- package/dist/mcp/manager.js +276 -0
- package/dist/mcp/tools.d.ts +54 -0
- package/dist/mcp/tools.js +99 -0
- package/dist/mcp/types.d.ts +150 -0
- package/dist/mcp/types.js +40 -0
- package/dist/memory/index.d.ts +8 -0
- package/dist/memory/index.js +7 -0
- package/dist/memory/loader.d.ts +114 -0
- package/dist/memory/loader.js +463 -0
- package/dist/memory/types.d.ts +182 -0
- package/dist/memory/types.js +8 -0
- package/dist/messages/index.d.ts +82 -0
- package/dist/messages/index.js +155 -0
- package/dist/permissions/index.d.ts +5 -0
- package/dist/permissions/index.js +4 -0
- package/dist/permissions/manager.d.ts +125 -0
- package/dist/permissions/manager.js +379 -0
- package/dist/permissions/types.d.ts +162 -0
- package/dist/permissions/types.js +7 -0
- package/dist/providers/claude.d.ts +90 -0
- package/dist/providers/claude.js +348 -0
- package/dist/providers/index.d.ts +8 -0
- package/dist/providers/index.js +11 -0
- package/dist/providers/mock.d.ts +133 -0
- package/dist/providers/mock.js +204 -0
- package/dist/providers/types.d.ts +168 -0
- package/dist/providers/types.js +4 -0
- package/dist/rate-limit/index.d.ts +45 -0
- package/dist/rate-limit/index.js +47 -0
- package/dist/rate-limit/limiter.d.ts +104 -0
- package/dist/rate-limit/limiter.js +326 -0
- package/dist/rate-limit/provider-wrapper.d.ts +112 -0
- package/dist/rate-limit/provider-wrapper.js +201 -0
- package/dist/rate-limit/retry.d.ts +108 -0
- package/dist/rate-limit/retry.js +287 -0
- package/dist/rate-limit/types.d.ts +181 -0
- package/dist/rate-limit/types.js +22 -0
- package/dist/rehearsal/file-analyzer.d.ts +22 -0
- package/dist/rehearsal/file-analyzer.js +351 -0
- package/dist/rehearsal/git-analyzer.d.ts +22 -0
- package/dist/rehearsal/git-analyzer.js +472 -0
- package/dist/rehearsal/index.d.ts +35 -0
- package/dist/rehearsal/index.js +36 -0
- package/dist/rehearsal/manager.d.ts +100 -0
- package/dist/rehearsal/manager.js +290 -0
- package/dist/rehearsal/types.d.ts +235 -0
- package/dist/rehearsal/types.js +8 -0
- package/dist/skills/index.d.ts +160 -0
- package/dist/skills/index.js +282 -0
- package/dist/state/agent-state.d.ts +41 -0
- package/dist/state/agent-state.js +88 -0
- package/dist/state/checkpointer.d.ts +110 -0
- package/dist/state/checkpointer.js +362 -0
- package/dist/state/errors.d.ts +66 -0
- package/dist/state/errors.js +88 -0
- package/dist/state/index.d.ts +35 -0
- package/dist/state/index.js +37 -0
- package/dist/state/serializer.d.ts +55 -0
- package/dist/state/serializer.js +172 -0
- package/dist/state/types.d.ts +312 -0
- package/dist/state/types.js +14 -0
- package/dist/tools/builtin/bash-output.d.ts +61 -0
- package/dist/tools/builtin/bash-output.js +90 -0
- package/dist/tools/builtin/bash.d.ts +150 -0
- package/dist/tools/builtin/bash.js +354 -0
- package/dist/tools/builtin/edit.d.ts +50 -0
- package/dist/tools/builtin/edit.js +215 -0
- package/dist/tools/builtin/glob.d.ts +62 -0
- package/dist/tools/builtin/glob.js +244 -0
- package/dist/tools/builtin/grep.d.ts +74 -0
- package/dist/tools/builtin/grep.js +363 -0
- package/dist/tools/builtin/index.d.ts +44 -0
- package/dist/tools/builtin/index.js +69 -0
- package/dist/tools/builtin/kill-shell.d.ts +44 -0
- package/dist/tools/builtin/kill-shell.js +80 -0
- package/dist/tools/builtin/read-file.d.ts +57 -0
- package/dist/tools/builtin/read-file.js +184 -0
- package/dist/tools/builtin/shell-manager.d.ts +176 -0
- package/dist/tools/builtin/shell-manager.js +337 -0
- package/dist/tools/builtin/task.d.ts +202 -0
- package/dist/tools/builtin/task.js +350 -0
- package/dist/tools/builtin/todo.d.ts +207 -0
- package/dist/tools/builtin/todo.js +453 -0
- package/dist/tools/builtin/utils.d.ts +27 -0
- package/dist/tools/builtin/utils.js +70 -0
- package/dist/tools/builtin/web-fetch.d.ts +96 -0
- package/dist/tools/builtin/web-fetch.js +290 -0
- package/dist/tools/builtin/write-file.d.ts +54 -0
- package/dist/tools/builtin/write-file.js +147 -0
- package/dist/tools/define.d.ts +60 -0
- package/dist/tools/define.js +65 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.js +37 -0
- package/dist/tools/registry.d.ts +79 -0
- package/dist/tools/registry.js +151 -0
- package/dist/tools/types.d.ts +59 -0
- package/dist/tools/types.js +4 -0
- package/dist/tracing/hooks.d.ts +58 -0
- package/dist/tracing/hooks.js +377 -0
- package/dist/tracing/index.d.ts +51 -0
- package/dist/tracing/index.js +55 -0
- package/dist/tracing/logging.d.ts +78 -0
- package/dist/tracing/logging.js +310 -0
- package/dist/tracing/manager.d.ts +160 -0
- package/dist/tracing/manager.js +468 -0
- package/dist/tracing/otel.d.ts +102 -0
- package/dist/tracing/otel.js +246 -0
- package/dist/tracing/types.d.ts +346 -0
- package/dist/tracing/types.js +38 -0
- package/dist/utils/index.d.ts +23 -0
- package/dist/utils/index.js +44 -0
- 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
|
+
}
|