llmz 0.0.13 → 0.0.15

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 (52) hide show
  1. package/CLAUDE.md +363 -0
  2. package/README.md +61 -34
  3. package/dist/abort-signal.d.ts +40 -0
  4. package/dist/chat.d.ts +325 -0
  5. package/dist/{chunk-KH6JQYQA.js → chunk-2D2DE7CD.js} +2 -2
  6. package/dist/chunk-3G3BS5IA.cjs +256 -0
  7. package/dist/{chunk-SNDVQU5A.js → chunk-3JYCCI4S.js} +1 -1
  8. package/dist/chunk-A7QHWVD7.js +493 -0
  9. package/dist/{chunk-IH2WQFO5.js → chunk-EE6NVDID.js} +1 -1
  10. package/dist/{chunk-4L6D2A6O.cjs → chunk-FZJHYLM2.cjs} +14 -14
  11. package/dist/{chunk-JGVAZO4X.cjs → chunk-GZPN7RGH.cjs} +2 -2
  12. package/dist/{chunk-SHJDRZF5.cjs → chunk-PIDLNYIP.cjs} +25 -25
  13. package/dist/{chunk-PRVFVXT4.js → chunk-RBRTK37G.js} +383 -4
  14. package/dist/{chunk-HJKOSEH2.cjs → chunk-TCRRSS44.cjs} +397 -18
  15. package/dist/chunk-VPTFUOIK.js +256 -0
  16. package/dist/{chunk-276Q6EWP.cjs → chunk-WHNOR4ZU.cjs} +3 -0
  17. package/dist/chunk-XGJOEQMW.cjs +493 -0
  18. package/dist/{chunk-4MNIJGK6.js → chunk-ZORRILUV.js} +3 -0
  19. package/dist/context.d.ts +412 -4
  20. package/dist/{dual-modes-T53P72CH.js → dual-modes-7FI4T35O.js} +3 -3
  21. package/dist/{dual-modes-VLIGPIHX.cjs → dual-modes-OFHV2C3X.cjs} +4 -4
  22. package/dist/exit-XAYKJ6TR.cjs +8 -0
  23. package/dist/{exit-YORW76T3.js → exit-YLO7BY7Z.js} +2 -2
  24. package/dist/exit.d.ts +369 -2
  25. package/dist/index.cjs +253 -28
  26. package/dist/index.d.ts +71 -1
  27. package/dist/index.js +242 -17
  28. package/dist/{llmz-ROOX7RYI.js → llmz-67EZPJ4E.js} +113 -39
  29. package/dist/{llmz-QLZBDG2Z.cjs → llmz-WVNKAMCP.cjs} +123 -49
  30. package/dist/llmz.d.ts +142 -5
  31. package/dist/objects.d.ts +350 -1
  32. package/dist/result.d.ts +809 -6
  33. package/dist/snapshots.d.ts +181 -1
  34. package/dist/{tool-QP4MVRWI.cjs → tool-O4SFRIE4.cjs} +4 -4
  35. package/dist/{tool-N6ODRRGH.js → tool-PCOYOCRH.js} +3 -3
  36. package/dist/tool.d.ts +470 -2
  37. package/dist/{truncator-IY2MXOMC.js → truncator-BSP6PQPC.js} +2 -2
  38. package/dist/truncator-W3NXBLYJ.cjs +10 -0
  39. package/dist/types.d.ts +3 -0
  40. package/dist/{typings-GDMY6VY2.js → typings-WYHEFCYB.js} +2 -2
  41. package/dist/{typings-2CPHOFDN.cjs → typings-Y45GMPZT.cjs} +3 -3
  42. package/dist/utils-L5QAQXV2.cjs +39 -0
  43. package/dist/{utils-N24IHDFA.js → utils-RQHQ2KOG.js} +1 -1
  44. package/docs/TODO.md +919 -0
  45. package/package.json +3 -3
  46. package/dist/chunk-C6WNNTEV.cjs +0 -212
  47. package/dist/chunk-GWFYZDUR.cjs +0 -105
  48. package/dist/chunk-JAGB2AOU.js +0 -212
  49. package/dist/chunk-JMSZKB4T.js +0 -105
  50. package/dist/exit-TRXEU4OU.cjs +0 -8
  51. package/dist/truncator-DUMWEGQO.cjs +0 -10
  52. package/dist/utils-A7WNEFTA.cjs +0 -39
package/dist/index.js CHANGED
@@ -8,15 +8,15 @@ import {
8
8
  SuccessExecutionResult,
9
9
  ThinkExit,
10
10
  getValue
11
- } from "./chunk-PRVFVXT4.js";
12
- import "./chunk-KH6JQYQA.js";
11
+ } from "./chunk-RBRTK37G.js";
12
+ import "./chunk-2D2DE7CD.js";
13
13
  import {
14
14
  Tool
15
- } from "./chunk-JAGB2AOU.js";
15
+ } from "./chunk-A7QHWVD7.js";
16
16
  import {
17
17
  formatTypings,
18
18
  getTypings
19
- } from "./chunk-IH2WQFO5.js";
19
+ } from "./chunk-EE6NVDID.js";
20
20
  import {
21
21
  CodeFormattingError,
22
22
  LoopExceededError,
@@ -26,7 +26,7 @@ import {
26
26
  import "./chunk-JQBT7UWN.js";
27
27
  import {
28
28
  Exit
29
- } from "./chunk-JMSZKB4T.js";
29
+ } from "./chunk-VPTFUOIK.js";
30
30
  import {
31
31
  Component,
32
32
  assertValidComponent,
@@ -35,12 +35,16 @@ import {
35
35
  renderToTsx
36
36
  } from "./chunk-GGWM6X2K.js";
37
37
  import "./chunk-ORQP26SZ.js";
38
- import "./chunk-SNDVQU5A.js";
38
+ import {
39
+ wrapContent
40
+ } from "./chunk-3JYCCI4S.js";
39
41
  import {
40
42
  escapeString,
41
43
  getMultilineComment,
42
- isValidIdentifier
43
- } from "./chunk-4MNIJGK6.js";
44
+ isValidIdentifier,
45
+ toValidFunctionName,
46
+ toValidObjectName
47
+ } from "./chunk-ZORRILUV.js";
44
48
  import {
45
49
  cloneDeep_default,
46
50
  upperFirst_default
@@ -307,6 +311,62 @@ var ObjectInstance = class {
307
311
  properties;
308
312
  tools;
309
313
  metadata;
314
+ /**
315
+ * Creates a new ObjectInstance.
316
+ *
317
+ * @param props - Object configuration
318
+ * @param props.name - Unique object name (must be valid TypeScript identifier)
319
+ * @param props.description - Human-readable description of the object
320
+ * @param props.tools - Array of tools to group under this object namespace
321
+ * @param props.properties - Array of stateful properties for this object
322
+ * @param props.metadata - Additional metadata for the object
323
+ *
324
+ * @throws Error if name is not a valid identifier
325
+ * @throws Error if description is not a string
326
+ * @throws Error if metadata is not an object
327
+ * @throws Error if properties/tools are not arrays
328
+ * @throws Error if properties exceed 100 limit
329
+ * @throws Error if property names are duplicated or invalid
330
+ * @throws Error if property descriptions exceed 5000 characters
331
+ *
332
+ * @example
333
+ * ```typescript
334
+ * const userProfile = new ObjectInstance({
335
+ * name: 'user',
336
+ * description: 'User profile management',
337
+ * properties: [
338
+ * {
339
+ * name: 'name',
340
+ * value: 'John Doe',
341
+ * type: z.string().min(1),
342
+ * description: 'User full name',
343
+ * writable: true,
344
+ * },
345
+ * {
346
+ * name: 'email',
347
+ * value: null,
348
+ * type: z.string().email().nullable(),
349
+ * description: 'User email address',
350
+ * writable: true,
351
+ * },
352
+ * ],
353
+ * tools: [
354
+ * new Tool({
355
+ * name: 'updateProfile',
356
+ * input: z.object({ name: z.string(), email: z.string() }),
357
+ * handler: async ({ name, email }) => {
358
+ * // Update external system
359
+ * await updateUserInDatabase({ name, email })
360
+ * },
361
+ * }),
362
+ * ],
363
+ * metadata: {
364
+ * version: '1.0',
365
+ * category: 'user-management',
366
+ * },
367
+ * })
368
+ * ```
369
+ */
310
370
  constructor(props) {
311
371
  var _a;
312
372
  if (!isValidIdentifier(props.name)) {
@@ -368,9 +428,64 @@ var ObjectInstance = class {
368
428
  this.properties = props.properties;
369
429
  this.tools = Tool.withUniqueNames(props.tools ?? []);
370
430
  }
431
+ /**
432
+ * Generates TypeScript namespace declarations for this object.
433
+ *
434
+ * This method creates TypeScript definitions that are included in the LLM context
435
+ * to help it understand the available properties and tools. Properties become
436
+ * const declarations with appropriate Readonly/Writable types, and tools become
437
+ * function signatures.
438
+ *
439
+ * @returns Promise resolving to TypeScript namespace declaration
440
+ *
441
+ * @example
442
+ * ```typescript
443
+ * const obj = new ObjectInstance({
444
+ * name: 'user',
445
+ * properties: [
446
+ * { name: 'name', value: 'John', writable: true },
447
+ * { name: 'id', value: 123, writable: false },
448
+ * ],
449
+ * tools: [
450
+ * new Tool({
451
+ * name: 'save',
452
+ * input: z.object({ data: z.string() }),
453
+ * handler: async ({ data }) => { /* ... *\/ },
454
+ * }),
455
+ * ],
456
+ * })
457
+ *
458
+ * const typings = await obj.getTypings()
459
+ * console.log(typings)
460
+ * // Output:
461
+ * // export namespace user {
462
+ * // const name: Writable<string> = "John"
463
+ * // const id: Readonly<number> = 123
464
+ * // function save(args: { data: string }): Promise<void>
465
+ * // }
466
+ * ```
467
+ */
371
468
  async getTypings() {
372
469
  return getObjectTypings(this).withProperties().withTools().build();
373
470
  }
471
+ /**
472
+ * Converts this ObjectInstance to its JSON representation.
473
+ *
474
+ * This method serializes the object into a JSON format that includes its name,
475
+ * description, properties, tools, and metadata. It is used for serialization
476
+ * and transmission of the object state.
477
+ *
478
+ * @returns JSON representation of the ObjectInstance
479
+ */
480
+ toJSON() {
481
+ return {
482
+ name: this.name,
483
+ description: this.description,
484
+ properties: this.properties,
485
+ tools: (this.tools ?? []).map((tool) => tool.toJSON()),
486
+ metadata: this.metadata
487
+ };
488
+ }
374
489
  };
375
490
  function getObjectTypings(obj) {
376
491
  let includeProperties = false;
@@ -866,31 +981,140 @@ var Chat = class {
866
981
  handler;
867
982
  transcript;
868
983
  components;
984
+ /**
985
+ * Creates a new Chat instance.
986
+ *
987
+ * @param props - Chat configuration
988
+ * @param props.handler - Function to handle agent messages (called for every agent output)
989
+ * @param props.components - Available UI components (static array or dynamic function)
990
+ * @param props.transcript - Conversation history (static array or dynamic function, defaults to empty)
991
+ *
992
+ * @example
993
+ * ```typescript
994
+ * // Basic chat with static configuration
995
+ * const chat = new Chat({
996
+ * handler: async (input) => {
997
+ * if (isComponent(input, DefaultComponents.Text)) {
998
+ * console.log('Agent:', input.children.join(''))
999
+ * }
1000
+ * },
1001
+ * components: [DefaultComponents.Text, DefaultComponents.Button],
1002
+ * transcript: [
1003
+ * { role: 'user', content: 'Hello', timestamp: Date.now() }
1004
+ * ],
1005
+ * })
1006
+ * ```
1007
+ *
1008
+ * @example
1009
+ * ```typescript
1010
+ * // Dynamic chat with functions for real-time updates
1011
+ * class MyChat extends Chat {
1012
+ * private messages: Transcript.Message[] = []
1013
+ *
1014
+ * constructor() {
1015
+ * super({
1016
+ * handler: (input) => this.handleMessage(input),
1017
+ *
1018
+ * // Dynamic components - can change during execution
1019
+ * components: () => [
1020
+ * DefaultComponents.Text,
1021
+ * DefaultComponents.Button,
1022
+ * ...this.getCustomComponents()
1023
+ * ],
1024
+ *
1025
+ * // Dynamic transcript - always reflects current state
1026
+ * transcript: () => this.messages,
1027
+ * })
1028
+ * }
1029
+ * }
1030
+ * ```
1031
+ */
869
1032
  constructor(props) {
870
1033
  this.handler = props.handler;
871
1034
  this.components = props.components;
872
1035
  this.transcript = props.transcript || [];
873
1036
  }
1037
+ /**
1038
+ * Called when an execution cycle completes, regardless of the outcome.
1039
+ *
1040
+ * Override this method to handle execution results, manage conversation flow,
1041
+ * or perform cleanup tasks. This is called after each `execute()` call completes,
1042
+ * whether it succeeds, fails, or is interrupted.
1043
+ *
1044
+ * @param result - The execution result containing status, iterations, and exit information
1045
+ *
1046
+ * @example
1047
+ * ```typescript
1048
+ * class MyChat extends Chat {
1049
+ * public result?: ExecutionResult
1050
+ *
1051
+ * onExecutionDone(result: ExecutionResult) {
1052
+ * // Store result for conversation flow control
1053
+ * this.result = result
1054
+ *
1055
+ * // Handle different result types
1056
+ * if (result.isSuccess()) {
1057
+ * console.log('✅ Execution completed successfully')
1058
+ * console.log('Exit:', result.output.exit_name)
1059
+ * } else if (result.isError()) {
1060
+ * console.error('❌ Execution failed:', result.output.error)
1061
+ * } else if (result.isInterrupted()) {
1062
+ * console.log('⏸️ Execution interrupted (partial result)')
1063
+ * }
1064
+ * }
1065
+ *
1066
+ * // Use stored result for conversation flow
1067
+ * isWaitingForInput(): boolean {
1068
+ * return this.result?.is(ListenExit) ?? false
1069
+ * }
1070
+ * }
1071
+ * ```
1072
+ *
1073
+ * @example
1074
+ * ```typescript
1075
+ * // CLIChat implementation example
1076
+ * class CLIChat extends Chat {
1077
+ * public status?: IterationStatus
1078
+ * public result?: ExecutionResult
1079
+ *
1080
+ * onExecutionDone(result: ExecutionResult) {
1081
+ * this.result = result
1082
+ * this.status = result.iterations.at(-1)?.status
1083
+ * }
1084
+ *
1085
+ * // Check if agent exited with specific exit type
1086
+ * hasExitedWith<R>(exit: Exit<R>): boolean {
1087
+ * return this.status?.type === 'exit_success' &&
1088
+ * this.status.exit_success.exit_name === exit.name
1089
+ * }
1090
+ * }
1091
+ * ```
1092
+ */
874
1093
  onExecutionDone(_result) {
875
1094
  }
876
1095
  };
877
1096
 
878
1097
  // src/index.ts
1098
+ var utils = {
1099
+ toValidObjectName,
1100
+ toValidFunctionName,
1101
+ wrapContent
1102
+ };
879
1103
  var execute = async (props) => {
880
- const { executeContext } = await import("./llmz-ROOX7RYI.js");
1104
+ const { executeContext } = await import("./llmz-67EZPJ4E.js");
881
1105
  return executeContext(props);
882
1106
  };
883
1107
  var init = async () => {
884
- await import("./llmz-ROOX7RYI.js");
1108
+ await import("./llmz-67EZPJ4E.js");
885
1109
  await import("./component-WFVDVSDK.js");
886
- await import("./tool-N6ODRRGH.js");
887
- await import("./exit-YORW76T3.js");
1110
+ await import("./tool-PCOYOCRH.js");
1111
+ await import("./exit-YLO7BY7Z.js");
888
1112
  await import("./jsx-AEHVFB3L.js");
889
1113
  await import("./vm-FLBMZUA2.js");
890
- await import("./utils-N24IHDFA.js");
891
- await import("./truncator-IY2MXOMC.js");
892
- await import("./typings-GDMY6VY2.js");
893
- await import("./dual-modes-T53P72CH.js");
1114
+ await import("./utils-RQHQ2KOG.js");
1115
+ await import("./truncator-BSP6PQPC.js");
1116
+ await import("./typings-WYHEFCYB.js");
1117
+ await import("./dual-modes-7FI4T35O.js");
894
1118
  };
895
1119
  export {
896
1120
  Chat,
@@ -917,5 +1141,6 @@ export {
917
1141
  init,
918
1142
  isAnyComponent,
919
1143
  isComponent,
920
- renderToTsx
1144
+ renderToTsx,
1145
+ utils
921
1146
  };
@@ -7,10 +7,10 @@ import {
7
7
  PartialExecutionResult,
8
8
  Snapshot,
9
9
  SuccessExecutionResult
10
- } from "./chunk-PRVFVXT4.js";
11
- import "./chunk-KH6JQYQA.js";
12
- import "./chunk-JAGB2AOU.js";
13
- import "./chunk-IH2WQFO5.js";
10
+ } from "./chunk-RBRTK37G.js";
11
+ import "./chunk-2D2DE7CD.js";
12
+ import "./chunk-A7QHWVD7.js";
13
+ import "./chunk-EE6NVDID.js";
14
14
  import {
15
15
  AssignmentError,
16
16
  CodeExecutionError,
@@ -24,16 +24,16 @@ import {
24
24
  import {
25
25
  cleanStackTrace
26
26
  } from "./chunk-JQBT7UWN.js";
27
- import "./chunk-JMSZKB4T.js";
27
+ import "./chunk-VPTFUOIK.js";
28
28
  import "./chunk-GGWM6X2K.js";
29
29
  import "./chunk-ORQP26SZ.js";
30
30
  import {
31
31
  truncateWrappedContent
32
- } from "./chunk-SNDVQU5A.js";
32
+ } from "./chunk-3JYCCI4S.js";
33
33
  import {
34
34
  init,
35
35
  stripInvalidIdentifiers
36
- } from "./chunk-4MNIJGK6.js";
36
+ } from "./chunk-ZORRILUV.js";
37
37
  import {
38
38
  clamp_default,
39
39
  isEqual_default,
@@ -46,6 +46,37 @@ import { Cognitive } from "@botpress/cognitive";
46
46
  import { z } from "@bpinternal/zui";
47
47
  import ms from "ms";
48
48
  import { ulid } from "ulid";
49
+
50
+ // src/abort-signal.ts
51
+ function createJoinedAbortController(signals) {
52
+ const controller = new AbortController();
53
+ const validSignals = signals.filter((signal) => signal != null);
54
+ if (validSignals.length === 0) {
55
+ return controller;
56
+ }
57
+ for (const signal of validSignals) {
58
+ if (signal.aborted) {
59
+ controller.abort(signal.reason);
60
+ return controller;
61
+ }
62
+ }
63
+ const abortListeners = [];
64
+ for (const signal of validSignals) {
65
+ const listener = () => {
66
+ controller.abort(signal.reason);
67
+ cleanup();
68
+ };
69
+ signal.addEventListener("abort", listener);
70
+ abortListeners.push(() => signal.removeEventListener("abort", listener));
71
+ }
72
+ const cleanup = () => {
73
+ abortListeners.forEach((removeListener) => removeListener());
74
+ };
75
+ controller.signal.addEventListener("abort", cleanup, { once: true });
76
+ return controller;
77
+ }
78
+
79
+ // src/llmz.ts
49
80
  var getErrorMessage = (err) => err instanceof Error ? err.message : JSON.stringify(err);
50
81
  var SLOW_TOOL_WARNING = ms("15s");
51
82
  var RESPONSE_LENGTH_BUFFER = {
@@ -70,7 +101,8 @@ var executeContext = async (props) => {
70
101
  };
71
102
  var _executeContext = async (props) => {
72
103
  var _a, _b, _c, _d;
73
- const { signal, onIterationEnd, onTrace, onExit, onBeforeExecution } = props;
104
+ const controller = createJoinedAbortController([props.signal]);
105
+ const { onIterationEnd, onTrace, onExit, onBeforeExecution, onAfterTool, onBeforeTool } = props;
74
106
  const cognitive = Cognitive.isCognitiveClient(props.client) ? props.client : new Cognitive({ client: props.client });
75
107
  const cleanups = [];
76
108
  const ctx = new Context({
@@ -91,14 +123,14 @@ var _executeContext = async (props) => {
91
123
  return new ErrorExecutionResult(ctx, new LoopExceededError());
92
124
  }
93
125
  const iteration = await ctx.nextIteration();
94
- if (signal == null ? void 0 : signal.aborted) {
126
+ if (controller.signal.aborted) {
95
127
  iteration.end({
96
128
  type: "aborted",
97
129
  aborted: {
98
- reason: signal.reason ?? "The operation was aborted"
130
+ reason: controller.signal.reason ?? "The operation was aborted"
99
131
  }
100
132
  });
101
- return new ErrorExecutionResult(ctx, signal.reason ?? "The operation was aborted");
133
+ return new ErrorExecutionResult(ctx, controller.signal.reason ?? "The operation was aborted");
102
134
  }
103
135
  cleanups.push(
104
136
  iteration.traces.onPush((traces) => {
@@ -112,9 +144,11 @@ var _executeContext = async (props) => {
112
144
  iteration,
113
145
  ctx,
114
146
  cognitive,
115
- abortSignal: signal,
147
+ controller,
116
148
  onExit,
117
- onBeforeExecution
149
+ onBeforeExecution,
150
+ onAfterTool,
151
+ onBeforeTool
118
152
  });
119
153
  } catch (err) {
120
154
  iteration.end({
@@ -126,7 +160,7 @@ var _executeContext = async (props) => {
126
160
  });
127
161
  }
128
162
  try {
129
- await (onIterationEnd == null ? void 0 : onIterationEnd(iteration));
163
+ await (onIterationEnd == null ? void 0 : onIterationEnd(iteration, controller));
130
164
  } catch (err) {
131
165
  console.error(err);
132
166
  }
@@ -164,9 +198,11 @@ var executeIteration = async ({
164
198
  iteration,
165
199
  ctx,
166
200
  cognitive,
167
- abortSignal,
201
+ controller,
168
202
  onExit,
169
- onBeforeExecution
203
+ onBeforeExecution,
204
+ onBeforeTool,
205
+ onAfterTool
170
206
  }) => {
171
207
  var _a, _b, _c, _d, _e;
172
208
  let startedAt = Date.now();
@@ -192,7 +228,7 @@ var executeIteration = async ({
192
228
  model: model.ref
193
229
  });
194
230
  const output = await cognitive.generateContent({
195
- signal: abortSignal,
231
+ signal: controller.signal,
196
232
  systemPrompt: (_a = messages.find((x) => x.role === "system")) == null ? void 0 : _a.content,
197
233
  model: model.ref,
198
234
  temperature: ctx.temperature,
@@ -208,7 +244,10 @@ var executeIteration = async ({
208
244
  iteration.code = assistantResponse.code.trim();
209
245
  if (typeof onBeforeExecution === "function") {
210
246
  try {
211
- await onBeforeExecution(iteration);
247
+ const hookRes = await onBeforeExecution(iteration, controller);
248
+ if (typeof (hookRes == null ? void 0 : hookRes.code) === "string" && hookRes.code.trim().length > 0) {
249
+ iteration.code = hookRes.code.trim();
250
+ }
212
251
  } catch (err) {
213
252
  if (err instanceof ThinkSignal) {
214
253
  return iteration.end({
@@ -288,19 +327,27 @@ var executeIteration = async ({
288
327
  });
289
328
  }
290
329
  for (const tool of obj.tools ?? []) {
291
- instance[tool.name] = wrapTool({ tool, traces, object: obj.name });
330
+ instance[tool.name] = wrapTool({
331
+ tool,
332
+ traces,
333
+ object: obj.name,
334
+ iteration,
335
+ beforeHook: onBeforeTool,
336
+ afterHook: onAfterTool,
337
+ controller
338
+ });
292
339
  }
293
340
  Object.preventExtensions(instance);
294
341
  Object.seal(instance);
295
342
  vmContext[obj.name] = instance;
296
343
  }
297
344
  for (const tool of iteration.tools) {
298
- const wrapped = wrapTool({ tool, traces });
345
+ const wrapped = wrapTool({ tool, traces, iteration, beforeHook: onBeforeTool, afterHook: onAfterTool, controller });
299
346
  for (const key of [tool.name, ...tool.aliases ?? []]) {
300
347
  vmContext[key] = wrapped;
301
348
  }
302
349
  }
303
- if (abortSignal == null ? void 0 : abortSignal.aborted) {
350
+ if (controller.signal.aborted) {
304
351
  traces.push({
305
352
  type: "abort_signal",
306
353
  started_at: Date.now(),
@@ -309,22 +356,26 @@ var executeIteration = async ({
309
356
  return iteration.end({
310
357
  type: "aborted",
311
358
  aborted: {
312
- reason: (abortSignal == null ? void 0 : abortSignal.reason) ?? "The operation was aborted"
359
+ reason: controller.signal.reason ?? "The operation was aborted"
313
360
  }
314
361
  });
315
362
  }
316
363
  startedAt = Date.now();
317
- const result = await runAsyncFunction(vmContext, iteration.code, traces, abortSignal, ctx.timeout).catch(
318
- (err) => {
319
- return {
320
- success: false,
321
- error: err,
322
- lines_executed: [],
323
- traces: [],
324
- variables: {}
325
- };
326
- }
327
- );
364
+ const result = await runAsyncFunction(
365
+ vmContext,
366
+ iteration.code,
367
+ traces,
368
+ controller.signal,
369
+ ctx.timeout
370
+ ).catch((err) => {
371
+ return {
372
+ success: false,
373
+ error: err,
374
+ lines_executed: [],
375
+ traces: [],
376
+ variables: {}
377
+ };
378
+ });
328
379
  if (result.error && result.error instanceof InvalidCodeError) {
329
380
  return iteration.end({
330
381
  type: "invalid_code_error",
@@ -348,11 +399,11 @@ var executeIteration = async ({
348
399
  }
349
400
  });
350
401
  }
351
- if (abortSignal == null ? void 0 : abortSignal.aborted) {
402
+ if (controller.signal.aborted) {
352
403
  return iteration.end({
353
404
  type: "aborted",
354
405
  aborted: {
355
- reason: (abortSignal == null ? void 0 : abortSignal.reason) ?? "The operation was aborted"
406
+ reason: controller.signal.reason ?? "The operation was aborted"
356
407
  }
357
408
  });
358
409
  }
@@ -462,7 +513,7 @@ var executeIteration = async ({
462
513
  }
463
514
  });
464
515
  };
465
- function wrapTool({ tool, traces, object }) {
516
+ function wrapTool({ tool, traces, object, iteration, beforeHook, afterHook, controller }) {
466
517
  const getToolInput = (input) => tool.zInput.safeParse(input).data ?? input;
467
518
  return function(input) {
468
519
  const toolCallId = `tcall_${ulid()}`;
@@ -510,9 +561,32 @@ function wrapTool({ tool, traces, object }) {
510
561
  return false;
511
562
  };
512
563
  try {
513
- const result = tool.execute(input, {
514
- callId: toolCallId
515
- });
564
+ const withHooks = async (input2) => {
565
+ const beforeRes = await (beforeHook == null ? void 0 : beforeHook({
566
+ iteration,
567
+ tool,
568
+ input: input2,
569
+ controller
570
+ }));
571
+ if (typeof (beforeRes == null ? void 0 : beforeRes.input) !== "undefined") {
572
+ input2 = beforeRes.input;
573
+ }
574
+ let output2 = await tool.execute(input2, {
575
+ callId: toolCallId
576
+ });
577
+ const afterRes = await (afterHook == null ? void 0 : afterHook({
578
+ iteration,
579
+ tool,
580
+ input: input2,
581
+ output: output2,
582
+ controller
583
+ }));
584
+ if (typeof (afterRes == null ? void 0 : afterRes.output) !== "undefined") {
585
+ output2 = afterRes.output;
586
+ }
587
+ return output2;
588
+ };
589
+ const result = withHooks(input);
516
590
  if (result instanceof Promise || (result == null ? void 0 : result.then) && (result == null ? void 0 : result.catch)) {
517
591
  return result.then((res) => {
518
592
  output = res;