llmist 1.7.0 → 2.1.0

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/dist/index.cjs CHANGED
@@ -671,6 +671,44 @@ ${this.endPrefix}`
671
671
  }
672
672
  });
673
673
 
674
+ // src/gadgets/exceptions.ts
675
+ var BreakLoopException, HumanInputException, TimeoutException, AbortError;
676
+ var init_exceptions = __esm({
677
+ "src/gadgets/exceptions.ts"() {
678
+ "use strict";
679
+ BreakLoopException = class extends Error {
680
+ constructor(message) {
681
+ super(message ?? "Agent loop terminated by gadget");
682
+ this.name = "BreakLoopException";
683
+ }
684
+ };
685
+ HumanInputException = class extends Error {
686
+ question;
687
+ constructor(question) {
688
+ super(`Human input required: ${question}`);
689
+ this.name = "HumanInputException";
690
+ this.question = question;
691
+ }
692
+ };
693
+ TimeoutException = class extends Error {
694
+ timeoutMs;
695
+ gadgetName;
696
+ constructor(gadgetName, timeoutMs) {
697
+ super(`Gadget '${gadgetName}' execution exceeded timeout of ${timeoutMs}ms`);
698
+ this.name = "TimeoutException";
699
+ this.gadgetName = gadgetName;
700
+ this.timeoutMs = timeoutMs;
701
+ }
702
+ };
703
+ AbortError = class extends Error {
704
+ constructor(message) {
705
+ super(message || "Gadget execution was aborted");
706
+ this.name = "AbortError";
707
+ }
708
+ };
709
+ }
710
+ });
711
+
674
712
  // src/logging/logger.ts
675
713
  function parseLogLevel(value) {
676
714
  if (!value) {
@@ -943,6 +981,7 @@ var init_gadget = __esm({
943
981
  "src/gadgets/gadget.ts"() {
944
982
  "use strict";
945
983
  init_constants();
984
+ init_exceptions();
946
985
  init_schema_to_json();
947
986
  init_schema_validator();
948
987
  BaseGadget = class {
@@ -972,6 +1011,136 @@ var init_gadget = __esm({
972
1011
  * while maintaining runtime compatibility.
973
1012
  */
974
1013
  examples;
1014
+ /**
1015
+ * Throws an AbortError if the execution has been aborted.
1016
+ *
1017
+ * Call this at key checkpoints in long-running gadgets to allow early exit
1018
+ * when the gadget has been cancelled (e.g., due to timeout). This enables
1019
+ * resource cleanup and prevents unnecessary work after cancellation.
1020
+ *
1021
+ * @param ctx - The execution context containing the abort signal
1022
+ * @throws AbortError if ctx.signal.aborted is true
1023
+ *
1024
+ * @example
1025
+ * ```typescript
1026
+ * class DataProcessor extends Gadget({
1027
+ * description: 'Processes data in multiple steps',
1028
+ * schema: z.object({ items: z.array(z.string()) }),
1029
+ * }) {
1030
+ * async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {
1031
+ * const results: string[] = [];
1032
+ *
1033
+ * for (const item of params.items) {
1034
+ * // Check before each expensive operation
1035
+ * this.throwIfAborted(ctx);
1036
+ *
1037
+ * results.push(await this.processItem(item));
1038
+ * }
1039
+ *
1040
+ * return results.join(', ');
1041
+ * }
1042
+ * }
1043
+ * ```
1044
+ */
1045
+ throwIfAborted(ctx) {
1046
+ if (ctx?.signal?.aborted) {
1047
+ throw new AbortError();
1048
+ }
1049
+ }
1050
+ /**
1051
+ * Register a cleanup function to run when execution is aborted (timeout or cancellation).
1052
+ * The cleanup function is called immediately if the signal is already aborted.
1053
+ * Errors thrown by the cleanup function are silently ignored.
1054
+ *
1055
+ * Use this to clean up resources like browser instances, database connections,
1056
+ * or child processes when the gadget is cancelled due to timeout.
1057
+ *
1058
+ * @param ctx - The execution context containing the abort signal
1059
+ * @param cleanup - Function to run on abort (can be sync or async)
1060
+ *
1061
+ * @example
1062
+ * ```typescript
1063
+ * class BrowserGadget extends Gadget({
1064
+ * description: 'Fetches web page content',
1065
+ * schema: z.object({ url: z.string() }),
1066
+ * }) {
1067
+ * async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {
1068
+ * const browser = await chromium.launch();
1069
+ * this.onAbort(ctx, () => browser.close());
1070
+ *
1071
+ * const page = await browser.newPage();
1072
+ * this.onAbort(ctx, () => page.close());
1073
+ *
1074
+ * await page.goto(params.url);
1075
+ * const content = await page.content();
1076
+ *
1077
+ * await browser.close();
1078
+ * return content;
1079
+ * }
1080
+ * }
1081
+ * ```
1082
+ */
1083
+ onAbort(ctx, cleanup) {
1084
+ if (!ctx?.signal) return;
1085
+ const safeCleanup = () => {
1086
+ try {
1087
+ const result = cleanup();
1088
+ if (result && typeof result === "object" && "catch" in result) {
1089
+ result.catch(() => {
1090
+ });
1091
+ }
1092
+ } catch {
1093
+ }
1094
+ };
1095
+ if (ctx.signal.aborted) {
1096
+ safeCleanup();
1097
+ return;
1098
+ }
1099
+ ctx.signal.addEventListener("abort", safeCleanup, { once: true });
1100
+ }
1101
+ /**
1102
+ * Create an AbortController linked to the execution context's signal.
1103
+ * When the parent signal aborts, the returned controller also aborts with the same reason.
1104
+ *
1105
+ * Useful for passing abort signals to child operations like fetch() while still
1106
+ * being able to abort them independently if needed.
1107
+ *
1108
+ * @param ctx - The execution context containing the parent abort signal
1109
+ * @returns A new AbortController linked to the parent signal
1110
+ *
1111
+ * @example
1112
+ * ```typescript
1113
+ * class FetchGadget extends Gadget({
1114
+ * description: 'Fetches data from URL',
1115
+ * schema: z.object({ url: z.string() }),
1116
+ * }) {
1117
+ * async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {
1118
+ * const controller = this.createLinkedAbortController(ctx);
1119
+ *
1120
+ * // fetch() will automatically abort when parent times out
1121
+ * const response = await fetch(params.url, { signal: controller.signal });
1122
+ * return response.text();
1123
+ * }
1124
+ * }
1125
+ * ```
1126
+ */
1127
+ createLinkedAbortController(ctx) {
1128
+ const controller = new AbortController();
1129
+ if (ctx?.signal) {
1130
+ if (ctx.signal.aborted) {
1131
+ controller.abort(ctx.signal.reason);
1132
+ } else {
1133
+ ctx.signal.addEventListener(
1134
+ "abort",
1135
+ () => {
1136
+ controller.abort(ctx.signal.reason);
1137
+ },
1138
+ { once: true }
1139
+ );
1140
+ }
1141
+ }
1142
+ return controller;
1143
+ }
975
1144
  /**
976
1145
  * Auto-generated instruction text for the LLM.
977
1146
  * Combines name, description, and parameter schema into a formatted instruction.
@@ -1039,8 +1208,8 @@ function createGadget(config) {
1039
1208
  parameterSchema = config.schema;
1040
1209
  timeoutMs = config.timeoutMs;
1041
1210
  examples = config.examples;
1042
- execute(params) {
1043
- return config.execute(params);
1211
+ execute(params, ctx) {
1212
+ return config.execute(params, ctx);
1044
1213
  }
1045
1214
  }
1046
1215
  return new DynamicGadget();
@@ -2376,6 +2545,162 @@ var init_block_params = __esm({
2376
2545
  }
2377
2546
  });
2378
2547
 
2548
+ // src/gadgets/cost-reporting-client.ts
2549
+ var CostReportingLLMistWrapper;
2550
+ var init_cost_reporting_client = __esm({
2551
+ "src/gadgets/cost-reporting-client.ts"() {
2552
+ "use strict";
2553
+ init_model_shortcuts();
2554
+ CostReportingLLMistWrapper = class {
2555
+ constructor(client, reportCost) {
2556
+ this.client = client;
2557
+ this.reportCost = reportCost;
2558
+ }
2559
+ /**
2560
+ * Access to model registry for cost estimation.
2561
+ */
2562
+ get modelRegistry() {
2563
+ return this.client.modelRegistry;
2564
+ }
2565
+ /**
2566
+ * Quick completion with automatic cost reporting.
2567
+ *
2568
+ * Streams internally to track token usage, then reports the calculated cost.
2569
+ *
2570
+ * @param prompt - User prompt
2571
+ * @param options - Optional configuration (model, temperature, etc.)
2572
+ * @returns Complete text response
2573
+ */
2574
+ async complete(prompt, options) {
2575
+ const model = resolveModel(options?.model ?? "haiku");
2576
+ let result = "";
2577
+ let inputTokens = 0;
2578
+ let outputTokens = 0;
2579
+ let cachedInputTokens = 0;
2580
+ let cacheCreationInputTokens = 0;
2581
+ const messages = [
2582
+ ...options?.systemPrompt ? [{ role: "system", content: options.systemPrompt }] : [],
2583
+ { role: "user", content: prompt }
2584
+ ];
2585
+ for await (const chunk of this.client.stream({
2586
+ model,
2587
+ messages,
2588
+ temperature: options?.temperature,
2589
+ maxTokens: options?.maxTokens
2590
+ })) {
2591
+ result += chunk.text ?? "";
2592
+ if (chunk.usage) {
2593
+ inputTokens = chunk.usage.inputTokens;
2594
+ outputTokens = chunk.usage.outputTokens;
2595
+ cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
2596
+ cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
2597
+ }
2598
+ }
2599
+ this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
2600
+ return result;
2601
+ }
2602
+ /**
2603
+ * Quick streaming with automatic cost reporting when stream completes.
2604
+ *
2605
+ * Yields text chunks as they arrive, then reports cost in finally block.
2606
+ *
2607
+ * @param prompt - User prompt
2608
+ * @param options - Optional configuration (model, temperature, etc.)
2609
+ * @returns Async generator yielding text chunks
2610
+ */
2611
+ async *streamText(prompt, options) {
2612
+ const model = resolveModel(options?.model ?? "haiku");
2613
+ let inputTokens = 0;
2614
+ let outputTokens = 0;
2615
+ let cachedInputTokens = 0;
2616
+ let cacheCreationInputTokens = 0;
2617
+ const messages = [
2618
+ ...options?.systemPrompt ? [{ role: "system", content: options.systemPrompt }] : [],
2619
+ { role: "user", content: prompt }
2620
+ ];
2621
+ try {
2622
+ for await (const chunk of this.client.stream({
2623
+ model,
2624
+ messages,
2625
+ temperature: options?.temperature,
2626
+ maxTokens: options?.maxTokens
2627
+ })) {
2628
+ if (chunk.text) {
2629
+ yield chunk.text;
2630
+ }
2631
+ if (chunk.usage) {
2632
+ inputTokens = chunk.usage.inputTokens;
2633
+ outputTokens = chunk.usage.outputTokens;
2634
+ cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
2635
+ cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
2636
+ }
2637
+ }
2638
+ } finally {
2639
+ this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
2640
+ }
2641
+ }
2642
+ /**
2643
+ * Low-level stream access with automatic cost reporting.
2644
+ *
2645
+ * Returns a wrapped stream that reports costs when iteration completes.
2646
+ *
2647
+ * @param options - Full LLM generation options
2648
+ * @returns Wrapped LLM stream that auto-reports costs
2649
+ */
2650
+ stream(options) {
2651
+ return this.createCostReportingStream(options);
2652
+ }
2653
+ /**
2654
+ * Creates a wrapped stream that tracks usage and reports costs on completion.
2655
+ */
2656
+ createCostReportingStream(options) {
2657
+ const innerStream = this.client.stream(options);
2658
+ const reportCostFromUsage = this.reportCostFromUsage.bind(this);
2659
+ const model = options.model;
2660
+ async function* costReportingWrapper() {
2661
+ let inputTokens = 0;
2662
+ let outputTokens = 0;
2663
+ let cachedInputTokens = 0;
2664
+ let cacheCreationInputTokens = 0;
2665
+ try {
2666
+ for await (const chunk of innerStream) {
2667
+ if (chunk.usage) {
2668
+ inputTokens = chunk.usage.inputTokens;
2669
+ outputTokens = chunk.usage.outputTokens;
2670
+ cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
2671
+ cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
2672
+ }
2673
+ yield chunk;
2674
+ }
2675
+ } finally {
2676
+ if (inputTokens > 0 || outputTokens > 0) {
2677
+ reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
2678
+ }
2679
+ }
2680
+ }
2681
+ return costReportingWrapper();
2682
+ }
2683
+ /**
2684
+ * Calculates and reports cost from token usage.
2685
+ */
2686
+ reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens = 0, cacheCreationInputTokens = 0) {
2687
+ if (inputTokens === 0 && outputTokens === 0) return;
2688
+ const modelName = model.includes(":") ? model.split(":")[1] : model;
2689
+ const estimate = this.client.modelRegistry.estimateCost(
2690
+ modelName,
2691
+ inputTokens,
2692
+ outputTokens,
2693
+ cachedInputTokens,
2694
+ cacheCreationInputTokens
2695
+ );
2696
+ if (estimate && estimate.totalCost > 0) {
2697
+ this.reportCost(estimate.totalCost);
2698
+ }
2699
+ }
2700
+ };
2701
+ }
2702
+ });
2703
+
2379
2704
  // src/gadgets/error-formatter.ts
2380
2705
  var GadgetErrorFormatter;
2381
2706
  var init_error_formatter = __esm({
@@ -2459,38 +2784,6 @@ var init_error_formatter = __esm({
2459
2784
  }
2460
2785
  });
2461
2786
 
2462
- // src/gadgets/exceptions.ts
2463
- var BreakLoopException, HumanInputException, TimeoutException;
2464
- var init_exceptions = __esm({
2465
- "src/gadgets/exceptions.ts"() {
2466
- "use strict";
2467
- BreakLoopException = class extends Error {
2468
- constructor(message) {
2469
- super(message ?? "Agent loop terminated by gadget");
2470
- this.name = "BreakLoopException";
2471
- }
2472
- };
2473
- HumanInputException = class extends Error {
2474
- question;
2475
- constructor(question) {
2476
- super(`Human input required: ${question}`);
2477
- this.name = "HumanInputException";
2478
- this.question = question;
2479
- }
2480
- };
2481
- TimeoutException = class extends Error {
2482
- timeoutMs;
2483
- gadgetName;
2484
- constructor(gadgetName, timeoutMs) {
2485
- super(`Gadget '${gadgetName}' execution exceeded timeout of ${timeoutMs}ms`);
2486
- this.name = "TimeoutException";
2487
- this.gadgetName = gadgetName;
2488
- this.timeoutMs = timeoutMs;
2489
- }
2490
- };
2491
- }
2492
- });
2493
-
2494
2787
  // src/gadgets/parser.ts
2495
2788
  function stripMarkdownFences(content) {
2496
2789
  let cleaned = content.trim();
@@ -2676,14 +2969,16 @@ var init_executor = __esm({
2676
2969
  init_constants();
2677
2970
  init_logger();
2678
2971
  init_block_params();
2972
+ init_cost_reporting_client();
2679
2973
  init_error_formatter();
2680
2974
  init_exceptions();
2681
2975
  init_parser();
2682
2976
  GadgetExecutor = class {
2683
- constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions) {
2977
+ constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client) {
2684
2978
  this.registry = registry;
2685
2979
  this.onHumanInputRequired = onHumanInputRequired;
2686
2980
  this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
2981
+ this.client = client;
2687
2982
  this.logger = logger ?? createLogger({ name: "llmist:executor" });
2688
2983
  this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
2689
2984
  this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
@@ -2693,14 +2988,27 @@ var init_executor = __esm({
2693
2988
  argPrefix;
2694
2989
  /**
2695
2990
  * Creates a promise that rejects with a TimeoutException after the specified timeout.
2991
+ * Aborts the provided AbortController before rejecting, allowing gadgets to clean up.
2696
2992
  */
2697
- createTimeoutPromise(gadgetName, timeoutMs) {
2993
+ createTimeoutPromise(gadgetName, timeoutMs, abortController) {
2698
2994
  return new Promise((_, reject) => {
2699
2995
  setTimeout(() => {
2700
- reject(new TimeoutException(gadgetName, timeoutMs));
2996
+ const timeoutError = new TimeoutException(gadgetName, timeoutMs);
2997
+ abortController.abort(timeoutError.message);
2998
+ reject(timeoutError);
2701
2999
  }, timeoutMs);
2702
3000
  });
2703
3001
  }
3002
+ /**
3003
+ * Normalizes gadget execute result to consistent format.
3004
+ * Handles both string returns (backwards compat) and object returns with cost.
3005
+ */
3006
+ normalizeExecuteResult(raw) {
3007
+ if (typeof raw === "string") {
3008
+ return { result: raw, cost: 0 };
3009
+ }
3010
+ return { result: raw.result, cost: raw.cost ?? 0 };
3011
+ }
2704
3012
  // Execute a gadget call asynchronously
2705
3013
  async execute(call) {
2706
3014
  const startTime = Date.now();
@@ -2795,30 +3103,53 @@ var init_executor = __esm({
2795
3103
  validatedParameters = schemaAwareParameters;
2796
3104
  }
2797
3105
  const timeoutMs = gadget.timeoutMs ?? this.defaultGadgetTimeoutMs;
2798
- let result;
3106
+ const abortController = new AbortController();
3107
+ let callbackCost = 0;
3108
+ const reportCost = (amount) => {
3109
+ if (amount > 0) {
3110
+ callbackCost += amount;
3111
+ this.logger.debug("Gadget reported cost via callback", {
3112
+ gadgetName: call.gadgetName,
3113
+ amount,
3114
+ totalCallbackCost: callbackCost
3115
+ });
3116
+ }
3117
+ };
3118
+ const ctx = {
3119
+ reportCost,
3120
+ llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
3121
+ signal: abortController.signal
3122
+ };
3123
+ let rawResult;
2799
3124
  if (timeoutMs && timeoutMs > 0) {
2800
3125
  this.logger.debug("Executing gadget with timeout", {
2801
3126
  gadgetName: call.gadgetName,
2802
3127
  timeoutMs
2803
3128
  });
2804
- result = await Promise.race([
2805
- Promise.resolve(gadget.execute(validatedParameters)),
2806
- this.createTimeoutPromise(call.gadgetName, timeoutMs)
3129
+ rawResult = await Promise.race([
3130
+ Promise.resolve(gadget.execute(validatedParameters, ctx)),
3131
+ this.createTimeoutPromise(call.gadgetName, timeoutMs, abortController)
2807
3132
  ]);
2808
3133
  } else {
2809
- result = await Promise.resolve(gadget.execute(validatedParameters));
3134
+ rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
2810
3135
  }
3136
+ const { result, cost: returnCost } = this.normalizeExecuteResult(rawResult);
3137
+ const totalCost = callbackCost + returnCost;
2811
3138
  const executionTimeMs = Date.now() - startTime;
2812
3139
  this.logger.info("Gadget executed successfully", {
2813
3140
  gadgetName: call.gadgetName,
2814
3141
  invocationId: call.invocationId,
2815
- executionTimeMs
3142
+ executionTimeMs,
3143
+ cost: totalCost > 0 ? totalCost : void 0,
3144
+ callbackCost: callbackCost > 0 ? callbackCost : void 0,
3145
+ returnCost: returnCost > 0 ? returnCost : void 0
2816
3146
  });
2817
3147
  this.logger.debug("Gadget result", {
2818
3148
  gadgetName: call.gadgetName,
2819
3149
  invocationId: call.invocationId,
2820
3150
  parameters: validatedParameters,
2821
3151
  result,
3152
+ cost: totalCost,
2822
3153
  executionTimeMs
2823
3154
  });
2824
3155
  return {
@@ -2826,7 +3157,8 @@ var init_executor = __esm({
2826
3157
  invocationId: call.invocationId,
2827
3158
  parameters: validatedParameters,
2828
3159
  result,
2829
- executionTimeMs
3160
+ executionTimeMs,
3161
+ cost: totalCost
2830
3162
  };
2831
3163
  } catch (error) {
2832
3164
  if (error instanceof BreakLoopException) {
@@ -2857,6 +3189,19 @@ var init_executor = __esm({
2857
3189
  executionTimeMs: Date.now() - startTime
2858
3190
  };
2859
3191
  }
3192
+ if (error instanceof AbortError) {
3193
+ this.logger.info("Gadget execution was aborted", {
3194
+ gadgetName: call.gadgetName,
3195
+ executionTimeMs: Date.now() - startTime
3196
+ });
3197
+ return {
3198
+ gadgetName: call.gadgetName,
3199
+ invocationId: call.invocationId,
3200
+ parameters: validatedParameters,
3201
+ error: error.message,
3202
+ executionTimeMs: Date.now() - startTime
3203
+ };
3204
+ }
2860
3205
  if (error instanceof HumanInputException) {
2861
3206
  this.logger.info("Gadget requested human input", {
2862
3207
  gadgetName: call.gadgetName,
@@ -2983,7 +3328,8 @@ var init_stream_processor = __esm({
2983
3328
  options.onHumanInputRequired,
2984
3329
  this.logger.getSubLogger({ name: "executor" }),
2985
3330
  options.defaultGadgetTimeoutMs,
2986
- { argPrefix: options.gadgetArgPrefix }
3331
+ { argPrefix: options.gadgetArgPrefix },
3332
+ options.client
2987
3333
  );
2988
3334
  }
2989
3335
  /**
@@ -3250,6 +3596,7 @@ var init_stream_processor = __esm({
3250
3596
  error: result.error,
3251
3597
  executionTimeMs: result.executionTimeMs,
3252
3598
  breaksLoop: result.breaksLoop,
3599
+ cost: result.cost,
3253
3600
  logger: this.logger
3254
3601
  };
3255
3602
  await this.hooks.observers.onGadgetExecutionComplete(context);
@@ -3606,6 +3953,17 @@ var init_agent = __esm({
3606
3953
  llmOptions = { ...llmOptions, ...action.modifiedOptions };
3607
3954
  }
3608
3955
  }
3956
+ await this.safeObserve(async () => {
3957
+ if (this.hooks.observers?.onLLMCallReady) {
3958
+ const context = {
3959
+ iteration: currentIteration,
3960
+ maxIterations: this.maxIterations,
3961
+ options: llmOptions,
3962
+ logger: this.logger
3963
+ };
3964
+ await this.hooks.observers.onLLMCallReady(context);
3965
+ }
3966
+ });
3609
3967
  this.logger.info("Calling LLM", { model: this.model });
3610
3968
  this.logger.silly("LLM request details", {
3611
3969
  model: llmOptions.model,
@@ -3626,7 +3984,8 @@ var init_agent = __esm({
3626
3984
  onHumanInputRequired: this.onHumanInputRequired,
3627
3985
  stopOnGadgetError: this.stopOnGadgetError,
3628
3986
  shouldContinueAfterError: this.shouldContinueAfterError,
3629
- defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs
3987
+ defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
3988
+ client: this.client
3630
3989
  });
3631
3990
  const result = await processor.process(stream2);
3632
3991
  for (const output of result.outputs) {
@@ -6672,6 +7031,7 @@ ${endPrefix}`
6672
7031
  // src/index.ts
6673
7032
  var index_exports = {};
6674
7033
  __export(index_exports, {
7034
+ AbortError: () => AbortError,
6675
7035
  AgentBuilder: () => AgentBuilder,
6676
7036
  AnthropicMessagesProvider: () => AnthropicMessagesProvider,
6677
7037
  BaseGadget: () => BaseGadget,
@@ -7109,6 +7469,7 @@ var HookPresets = class _HookPresets {
7109
7469
  let totalInputTokens = 0;
7110
7470
  let totalOutputTokens = 0;
7111
7471
  let totalCost = 0;
7472
+ let totalGadgetCost = 0;
7112
7473
  const startTime = Date.now();
7113
7474
  return {
7114
7475
  observers: {
@@ -7146,7 +7507,7 @@ var HookPresets = class _HookPresets {
7146
7507
  totalInputTokens,
7147
7508
  totalOutputTokens,
7148
7509
  totalTokens: totalInputTokens + totalOutputTokens,
7149
- totalCost,
7510
+ totalCost: totalCost + totalGadgetCost,
7150
7511
  elapsedSeconds: Number(((Date.now() - startTime) / 1e3).toFixed(1))
7151
7512
  };
7152
7513
  if (onProgress) {
@@ -7159,6 +7520,12 @@ var HookPresets = class _HookPresets {
7159
7520
  `\u{1F4CA} Progress: Iteration #${stats.currentIteration} | ${formattedTokens} tokens | ${formattedCost} | ${stats.elapsedSeconds}s`
7160
7521
  );
7161
7522
  }
7523
+ },
7524
+ // Track gadget execution costs
7525
+ onGadgetExecutionComplete: async (ctx) => {
7526
+ if (ctx.cost && ctx.cost > 0) {
7527
+ totalGadgetCost += ctx.cost;
7528
+ }
7162
7529
  }
7163
7530
  }
7164
7531
  };
@@ -8402,6 +8769,7 @@ init_gadget();
8402
8769
  var import_node_stream = require("stream");
8403
8770
  // Annotate the CommonJS export names for ESM import in node:
8404
8771
  0 && (module.exports = {
8772
+ AbortError,
8405
8773
  AgentBuilder,
8406
8774
  AnthropicMessagesProvider,
8407
8775
  BaseGadget,