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.
@@ -738,6 +738,44 @@ ${this.endPrefix}`
738
738
  }
739
739
  });
740
740
 
741
+ // src/gadgets/exceptions.ts
742
+ var BreakLoopException, HumanInputException, TimeoutException, AbortError;
743
+ var init_exceptions = __esm({
744
+ "src/gadgets/exceptions.ts"() {
745
+ "use strict";
746
+ BreakLoopException = class extends Error {
747
+ constructor(message) {
748
+ super(message ?? "Agent loop terminated by gadget");
749
+ this.name = "BreakLoopException";
750
+ }
751
+ };
752
+ HumanInputException = class extends Error {
753
+ question;
754
+ constructor(question) {
755
+ super(`Human input required: ${question}`);
756
+ this.name = "HumanInputException";
757
+ this.question = question;
758
+ }
759
+ };
760
+ TimeoutException = class extends Error {
761
+ timeoutMs;
762
+ gadgetName;
763
+ constructor(gadgetName, timeoutMs) {
764
+ super(`Gadget '${gadgetName}' execution exceeded timeout of ${timeoutMs}ms`);
765
+ this.name = "TimeoutException";
766
+ this.gadgetName = gadgetName;
767
+ this.timeoutMs = timeoutMs;
768
+ }
769
+ };
770
+ AbortError = class extends Error {
771
+ constructor(message) {
772
+ super(message || "Gadget execution was aborted");
773
+ this.name = "AbortError";
774
+ }
775
+ };
776
+ }
777
+ });
778
+
741
779
  // src/gadgets/schema-to-json.ts
742
780
  import * as z2 from "zod";
743
781
  function schemaToJSONSchema(schema, options) {
@@ -930,6 +968,7 @@ var init_gadget = __esm({
930
968
  "src/gadgets/gadget.ts"() {
931
969
  "use strict";
932
970
  init_constants();
971
+ init_exceptions();
933
972
  init_schema_to_json();
934
973
  init_schema_validator();
935
974
  BaseGadget = class {
@@ -959,6 +998,136 @@ var init_gadget = __esm({
959
998
  * while maintaining runtime compatibility.
960
999
  */
961
1000
  examples;
1001
+ /**
1002
+ * Throws an AbortError if the execution has been aborted.
1003
+ *
1004
+ * Call this at key checkpoints in long-running gadgets to allow early exit
1005
+ * when the gadget has been cancelled (e.g., due to timeout). This enables
1006
+ * resource cleanup and prevents unnecessary work after cancellation.
1007
+ *
1008
+ * @param ctx - The execution context containing the abort signal
1009
+ * @throws AbortError if ctx.signal.aborted is true
1010
+ *
1011
+ * @example
1012
+ * ```typescript
1013
+ * class DataProcessor extends Gadget({
1014
+ * description: 'Processes data in multiple steps',
1015
+ * schema: z.object({ items: z.array(z.string()) }),
1016
+ * }) {
1017
+ * async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {
1018
+ * const results: string[] = [];
1019
+ *
1020
+ * for (const item of params.items) {
1021
+ * // Check before each expensive operation
1022
+ * this.throwIfAborted(ctx);
1023
+ *
1024
+ * results.push(await this.processItem(item));
1025
+ * }
1026
+ *
1027
+ * return results.join(', ');
1028
+ * }
1029
+ * }
1030
+ * ```
1031
+ */
1032
+ throwIfAborted(ctx) {
1033
+ if (ctx?.signal?.aborted) {
1034
+ throw new AbortError();
1035
+ }
1036
+ }
1037
+ /**
1038
+ * Register a cleanup function to run when execution is aborted (timeout or cancellation).
1039
+ * The cleanup function is called immediately if the signal is already aborted.
1040
+ * Errors thrown by the cleanup function are silently ignored.
1041
+ *
1042
+ * Use this to clean up resources like browser instances, database connections,
1043
+ * or child processes when the gadget is cancelled due to timeout.
1044
+ *
1045
+ * @param ctx - The execution context containing the abort signal
1046
+ * @param cleanup - Function to run on abort (can be sync or async)
1047
+ *
1048
+ * @example
1049
+ * ```typescript
1050
+ * class BrowserGadget extends Gadget({
1051
+ * description: 'Fetches web page content',
1052
+ * schema: z.object({ url: z.string() }),
1053
+ * }) {
1054
+ * async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {
1055
+ * const browser = await chromium.launch();
1056
+ * this.onAbort(ctx, () => browser.close());
1057
+ *
1058
+ * const page = await browser.newPage();
1059
+ * this.onAbort(ctx, () => page.close());
1060
+ *
1061
+ * await page.goto(params.url);
1062
+ * const content = await page.content();
1063
+ *
1064
+ * await browser.close();
1065
+ * return content;
1066
+ * }
1067
+ * }
1068
+ * ```
1069
+ */
1070
+ onAbort(ctx, cleanup) {
1071
+ if (!ctx?.signal) return;
1072
+ const safeCleanup = () => {
1073
+ try {
1074
+ const result = cleanup();
1075
+ if (result && typeof result === "object" && "catch" in result) {
1076
+ result.catch(() => {
1077
+ });
1078
+ }
1079
+ } catch {
1080
+ }
1081
+ };
1082
+ if (ctx.signal.aborted) {
1083
+ safeCleanup();
1084
+ return;
1085
+ }
1086
+ ctx.signal.addEventListener("abort", safeCleanup, { once: true });
1087
+ }
1088
+ /**
1089
+ * Create an AbortController linked to the execution context's signal.
1090
+ * When the parent signal aborts, the returned controller also aborts with the same reason.
1091
+ *
1092
+ * Useful for passing abort signals to child operations like fetch() while still
1093
+ * being able to abort them independently if needed.
1094
+ *
1095
+ * @param ctx - The execution context containing the parent abort signal
1096
+ * @returns A new AbortController linked to the parent signal
1097
+ *
1098
+ * @example
1099
+ * ```typescript
1100
+ * class FetchGadget extends Gadget({
1101
+ * description: 'Fetches data from URL',
1102
+ * schema: z.object({ url: z.string() }),
1103
+ * }) {
1104
+ * async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {
1105
+ * const controller = this.createLinkedAbortController(ctx);
1106
+ *
1107
+ * // fetch() will automatically abort when parent times out
1108
+ * const response = await fetch(params.url, { signal: controller.signal });
1109
+ * return response.text();
1110
+ * }
1111
+ * }
1112
+ * ```
1113
+ */
1114
+ createLinkedAbortController(ctx) {
1115
+ const controller = new AbortController();
1116
+ if (ctx?.signal) {
1117
+ if (ctx.signal.aborted) {
1118
+ controller.abort(ctx.signal.reason);
1119
+ } else {
1120
+ ctx.signal.addEventListener(
1121
+ "abort",
1122
+ () => {
1123
+ controller.abort(ctx.signal.reason);
1124
+ },
1125
+ { once: true }
1126
+ );
1127
+ }
1128
+ }
1129
+ return controller;
1130
+ }
962
1131
  /**
963
1132
  * Auto-generated instruction text for the LLM.
964
1133
  * Combines name, description, and parameter schema into a formatted instruction.
@@ -1026,8 +1195,8 @@ function createGadget(config) {
1026
1195
  parameterSchema = config.schema;
1027
1196
  timeoutMs = config.timeoutMs;
1028
1197
  examples = config.examples;
1029
- execute(params) {
1030
- return config.execute(params);
1198
+ execute(params, ctx) {
1199
+ return config.execute(params, ctx);
1031
1200
  }
1032
1201
  }
1033
1202
  return new DynamicGadget();
@@ -2363,6 +2532,162 @@ var init_block_params = __esm({
2363
2532
  }
2364
2533
  });
2365
2534
 
2535
+ // src/gadgets/cost-reporting-client.ts
2536
+ var CostReportingLLMistWrapper;
2537
+ var init_cost_reporting_client = __esm({
2538
+ "src/gadgets/cost-reporting-client.ts"() {
2539
+ "use strict";
2540
+ init_model_shortcuts();
2541
+ CostReportingLLMistWrapper = class {
2542
+ constructor(client, reportCost) {
2543
+ this.client = client;
2544
+ this.reportCost = reportCost;
2545
+ }
2546
+ /**
2547
+ * Access to model registry for cost estimation.
2548
+ */
2549
+ get modelRegistry() {
2550
+ return this.client.modelRegistry;
2551
+ }
2552
+ /**
2553
+ * Quick completion with automatic cost reporting.
2554
+ *
2555
+ * Streams internally to track token usage, then reports the calculated cost.
2556
+ *
2557
+ * @param prompt - User prompt
2558
+ * @param options - Optional configuration (model, temperature, etc.)
2559
+ * @returns Complete text response
2560
+ */
2561
+ async complete(prompt, options) {
2562
+ const model = resolveModel(options?.model ?? "haiku");
2563
+ let result = "";
2564
+ let inputTokens = 0;
2565
+ let outputTokens = 0;
2566
+ let cachedInputTokens = 0;
2567
+ let cacheCreationInputTokens = 0;
2568
+ const messages = [
2569
+ ...options?.systemPrompt ? [{ role: "system", content: options.systemPrompt }] : [],
2570
+ { role: "user", content: prompt }
2571
+ ];
2572
+ for await (const chunk of this.client.stream({
2573
+ model,
2574
+ messages,
2575
+ temperature: options?.temperature,
2576
+ maxTokens: options?.maxTokens
2577
+ })) {
2578
+ result += chunk.text ?? "";
2579
+ if (chunk.usage) {
2580
+ inputTokens = chunk.usage.inputTokens;
2581
+ outputTokens = chunk.usage.outputTokens;
2582
+ cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
2583
+ cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
2584
+ }
2585
+ }
2586
+ this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
2587
+ return result;
2588
+ }
2589
+ /**
2590
+ * Quick streaming with automatic cost reporting when stream completes.
2591
+ *
2592
+ * Yields text chunks as they arrive, then reports cost in finally block.
2593
+ *
2594
+ * @param prompt - User prompt
2595
+ * @param options - Optional configuration (model, temperature, etc.)
2596
+ * @returns Async generator yielding text chunks
2597
+ */
2598
+ async *streamText(prompt, options) {
2599
+ const model = resolveModel(options?.model ?? "haiku");
2600
+ let inputTokens = 0;
2601
+ let outputTokens = 0;
2602
+ let cachedInputTokens = 0;
2603
+ let cacheCreationInputTokens = 0;
2604
+ const messages = [
2605
+ ...options?.systemPrompt ? [{ role: "system", content: options.systemPrompt }] : [],
2606
+ { role: "user", content: prompt }
2607
+ ];
2608
+ try {
2609
+ for await (const chunk of this.client.stream({
2610
+ model,
2611
+ messages,
2612
+ temperature: options?.temperature,
2613
+ maxTokens: options?.maxTokens
2614
+ })) {
2615
+ if (chunk.text) {
2616
+ yield chunk.text;
2617
+ }
2618
+ if (chunk.usage) {
2619
+ inputTokens = chunk.usage.inputTokens;
2620
+ outputTokens = chunk.usage.outputTokens;
2621
+ cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
2622
+ cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
2623
+ }
2624
+ }
2625
+ } finally {
2626
+ this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
2627
+ }
2628
+ }
2629
+ /**
2630
+ * Low-level stream access with automatic cost reporting.
2631
+ *
2632
+ * Returns a wrapped stream that reports costs when iteration completes.
2633
+ *
2634
+ * @param options - Full LLM generation options
2635
+ * @returns Wrapped LLM stream that auto-reports costs
2636
+ */
2637
+ stream(options) {
2638
+ return this.createCostReportingStream(options);
2639
+ }
2640
+ /**
2641
+ * Creates a wrapped stream that tracks usage and reports costs on completion.
2642
+ */
2643
+ createCostReportingStream(options) {
2644
+ const innerStream = this.client.stream(options);
2645
+ const reportCostFromUsage = this.reportCostFromUsage.bind(this);
2646
+ const model = options.model;
2647
+ async function* costReportingWrapper() {
2648
+ let inputTokens = 0;
2649
+ let outputTokens = 0;
2650
+ let cachedInputTokens = 0;
2651
+ let cacheCreationInputTokens = 0;
2652
+ try {
2653
+ for await (const chunk of innerStream) {
2654
+ if (chunk.usage) {
2655
+ inputTokens = chunk.usage.inputTokens;
2656
+ outputTokens = chunk.usage.outputTokens;
2657
+ cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
2658
+ cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
2659
+ }
2660
+ yield chunk;
2661
+ }
2662
+ } finally {
2663
+ if (inputTokens > 0 || outputTokens > 0) {
2664
+ reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
2665
+ }
2666
+ }
2667
+ }
2668
+ return costReportingWrapper();
2669
+ }
2670
+ /**
2671
+ * Calculates and reports cost from token usage.
2672
+ */
2673
+ reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens = 0, cacheCreationInputTokens = 0) {
2674
+ if (inputTokens === 0 && outputTokens === 0) return;
2675
+ const modelName = model.includes(":") ? model.split(":")[1] : model;
2676
+ const estimate = this.client.modelRegistry.estimateCost(
2677
+ modelName,
2678
+ inputTokens,
2679
+ outputTokens,
2680
+ cachedInputTokens,
2681
+ cacheCreationInputTokens
2682
+ );
2683
+ if (estimate && estimate.totalCost > 0) {
2684
+ this.reportCost(estimate.totalCost);
2685
+ }
2686
+ }
2687
+ };
2688
+ }
2689
+ });
2690
+
2366
2691
  // src/gadgets/error-formatter.ts
2367
2692
  var GadgetErrorFormatter;
2368
2693
  var init_error_formatter = __esm({
@@ -2446,38 +2771,6 @@ var init_error_formatter = __esm({
2446
2771
  }
2447
2772
  });
2448
2773
 
2449
- // src/gadgets/exceptions.ts
2450
- var BreakLoopException, HumanInputException, TimeoutException;
2451
- var init_exceptions = __esm({
2452
- "src/gadgets/exceptions.ts"() {
2453
- "use strict";
2454
- BreakLoopException = class extends Error {
2455
- constructor(message) {
2456
- super(message ?? "Agent loop terminated by gadget");
2457
- this.name = "BreakLoopException";
2458
- }
2459
- };
2460
- HumanInputException = class extends Error {
2461
- question;
2462
- constructor(question) {
2463
- super(`Human input required: ${question}`);
2464
- this.name = "HumanInputException";
2465
- this.question = question;
2466
- }
2467
- };
2468
- TimeoutException = class extends Error {
2469
- timeoutMs;
2470
- gadgetName;
2471
- constructor(gadgetName, timeoutMs) {
2472
- super(`Gadget '${gadgetName}' execution exceeded timeout of ${timeoutMs}ms`);
2473
- this.name = "TimeoutException";
2474
- this.gadgetName = gadgetName;
2475
- this.timeoutMs = timeoutMs;
2476
- }
2477
- };
2478
- }
2479
- });
2480
-
2481
2774
  // src/gadgets/parser.ts
2482
2775
  function stripMarkdownFences(content) {
2483
2776
  let cleaned = content.trim();
@@ -2663,14 +2956,16 @@ var init_executor = __esm({
2663
2956
  init_constants();
2664
2957
  init_logger();
2665
2958
  init_block_params();
2959
+ init_cost_reporting_client();
2666
2960
  init_error_formatter();
2667
2961
  init_exceptions();
2668
2962
  init_parser();
2669
2963
  GadgetExecutor = class {
2670
- constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions) {
2964
+ constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client) {
2671
2965
  this.registry = registry;
2672
2966
  this.onHumanInputRequired = onHumanInputRequired;
2673
2967
  this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
2968
+ this.client = client;
2674
2969
  this.logger = logger ?? createLogger({ name: "llmist:executor" });
2675
2970
  this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
2676
2971
  this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
@@ -2680,14 +2975,27 @@ var init_executor = __esm({
2680
2975
  argPrefix;
2681
2976
  /**
2682
2977
  * Creates a promise that rejects with a TimeoutException after the specified timeout.
2978
+ * Aborts the provided AbortController before rejecting, allowing gadgets to clean up.
2683
2979
  */
2684
- createTimeoutPromise(gadgetName, timeoutMs) {
2980
+ createTimeoutPromise(gadgetName, timeoutMs, abortController) {
2685
2981
  return new Promise((_, reject) => {
2686
2982
  setTimeout(() => {
2687
- reject(new TimeoutException(gadgetName, timeoutMs));
2983
+ const timeoutError = new TimeoutException(gadgetName, timeoutMs);
2984
+ abortController.abort(timeoutError.message);
2985
+ reject(timeoutError);
2688
2986
  }, timeoutMs);
2689
2987
  });
2690
2988
  }
2989
+ /**
2990
+ * Normalizes gadget execute result to consistent format.
2991
+ * Handles both string returns (backwards compat) and object returns with cost.
2992
+ */
2993
+ normalizeExecuteResult(raw) {
2994
+ if (typeof raw === "string") {
2995
+ return { result: raw, cost: 0 };
2996
+ }
2997
+ return { result: raw.result, cost: raw.cost ?? 0 };
2998
+ }
2691
2999
  // Execute a gadget call asynchronously
2692
3000
  async execute(call) {
2693
3001
  const startTime = Date.now();
@@ -2782,30 +3090,53 @@ var init_executor = __esm({
2782
3090
  validatedParameters = schemaAwareParameters;
2783
3091
  }
2784
3092
  const timeoutMs = gadget.timeoutMs ?? this.defaultGadgetTimeoutMs;
2785
- let result;
3093
+ const abortController = new AbortController();
3094
+ let callbackCost = 0;
3095
+ const reportCost = (amount) => {
3096
+ if (amount > 0) {
3097
+ callbackCost += amount;
3098
+ this.logger.debug("Gadget reported cost via callback", {
3099
+ gadgetName: call.gadgetName,
3100
+ amount,
3101
+ totalCallbackCost: callbackCost
3102
+ });
3103
+ }
3104
+ };
3105
+ const ctx = {
3106
+ reportCost,
3107
+ llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
3108
+ signal: abortController.signal
3109
+ };
3110
+ let rawResult;
2786
3111
  if (timeoutMs && timeoutMs > 0) {
2787
3112
  this.logger.debug("Executing gadget with timeout", {
2788
3113
  gadgetName: call.gadgetName,
2789
3114
  timeoutMs
2790
3115
  });
2791
- result = await Promise.race([
2792
- Promise.resolve(gadget.execute(validatedParameters)),
2793
- this.createTimeoutPromise(call.gadgetName, timeoutMs)
3116
+ rawResult = await Promise.race([
3117
+ Promise.resolve(gadget.execute(validatedParameters, ctx)),
3118
+ this.createTimeoutPromise(call.gadgetName, timeoutMs, abortController)
2794
3119
  ]);
2795
3120
  } else {
2796
- result = await Promise.resolve(gadget.execute(validatedParameters));
3121
+ rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
2797
3122
  }
3123
+ const { result, cost: returnCost } = this.normalizeExecuteResult(rawResult);
3124
+ const totalCost = callbackCost + returnCost;
2798
3125
  const executionTimeMs = Date.now() - startTime;
2799
3126
  this.logger.info("Gadget executed successfully", {
2800
3127
  gadgetName: call.gadgetName,
2801
3128
  invocationId: call.invocationId,
2802
- executionTimeMs
3129
+ executionTimeMs,
3130
+ cost: totalCost > 0 ? totalCost : void 0,
3131
+ callbackCost: callbackCost > 0 ? callbackCost : void 0,
3132
+ returnCost: returnCost > 0 ? returnCost : void 0
2803
3133
  });
2804
3134
  this.logger.debug("Gadget result", {
2805
3135
  gadgetName: call.gadgetName,
2806
3136
  invocationId: call.invocationId,
2807
3137
  parameters: validatedParameters,
2808
3138
  result,
3139
+ cost: totalCost,
2809
3140
  executionTimeMs
2810
3141
  });
2811
3142
  return {
@@ -2813,7 +3144,8 @@ var init_executor = __esm({
2813
3144
  invocationId: call.invocationId,
2814
3145
  parameters: validatedParameters,
2815
3146
  result,
2816
- executionTimeMs
3147
+ executionTimeMs,
3148
+ cost: totalCost
2817
3149
  };
2818
3150
  } catch (error) {
2819
3151
  if (error instanceof BreakLoopException) {
@@ -2844,6 +3176,19 @@ var init_executor = __esm({
2844
3176
  executionTimeMs: Date.now() - startTime
2845
3177
  };
2846
3178
  }
3179
+ if (error instanceof AbortError) {
3180
+ this.logger.info("Gadget execution was aborted", {
3181
+ gadgetName: call.gadgetName,
3182
+ executionTimeMs: Date.now() - startTime
3183
+ });
3184
+ return {
3185
+ gadgetName: call.gadgetName,
3186
+ invocationId: call.invocationId,
3187
+ parameters: validatedParameters,
3188
+ error: error.message,
3189
+ executionTimeMs: Date.now() - startTime
3190
+ };
3191
+ }
2847
3192
  if (error instanceof HumanInputException) {
2848
3193
  this.logger.info("Gadget requested human input", {
2849
3194
  gadgetName: call.gadgetName,
@@ -2970,7 +3315,8 @@ var init_stream_processor = __esm({
2970
3315
  options.onHumanInputRequired,
2971
3316
  this.logger.getSubLogger({ name: "executor" }),
2972
3317
  options.defaultGadgetTimeoutMs,
2973
- { argPrefix: options.gadgetArgPrefix }
3318
+ { argPrefix: options.gadgetArgPrefix },
3319
+ options.client
2974
3320
  );
2975
3321
  }
2976
3322
  /**
@@ -3237,6 +3583,7 @@ var init_stream_processor = __esm({
3237
3583
  error: result.error,
3238
3584
  executionTimeMs: result.executionTimeMs,
3239
3585
  breaksLoop: result.breaksLoop,
3586
+ cost: result.cost,
3240
3587
  logger: this.logger
3241
3588
  };
3242
3589
  await this.hooks.observers.onGadgetExecutionComplete(context);
@@ -3593,6 +3940,17 @@ var init_agent = __esm({
3593
3940
  llmOptions = { ...llmOptions, ...action.modifiedOptions };
3594
3941
  }
3595
3942
  }
3943
+ await this.safeObserve(async () => {
3944
+ if (this.hooks.observers?.onLLMCallReady) {
3945
+ const context = {
3946
+ iteration: currentIteration,
3947
+ maxIterations: this.maxIterations,
3948
+ options: llmOptions,
3949
+ logger: this.logger
3950
+ };
3951
+ await this.hooks.observers.onLLMCallReady(context);
3952
+ }
3953
+ });
3596
3954
  this.logger.info("Calling LLM", { model: this.model });
3597
3955
  this.logger.silly("LLM request details", {
3598
3956
  model: llmOptions.model,
@@ -3613,7 +3971,8 @@ var init_agent = __esm({
3613
3971
  onHumanInputRequired: this.onHumanInputRequired,
3614
3972
  stopOnGadgetError: this.stopOnGadgetError,
3615
3973
  shouldContinueAfterError: this.shouldContinueAfterError,
3616
- defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs
3974
+ defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
3975
+ client: this.client
3617
3976
  });
3618
3977
  const result = await processor.process(stream2);
3619
3978
  for (const output of result.outputs) {
@@ -6700,10 +7059,18 @@ async function testGadget(gadget, params, options) {
6700
7059
  validatedParams = validationResult.data;
6701
7060
  }
6702
7061
  try {
6703
- const result = await Promise.resolve(gadget.execute(validatedParams));
7062
+ const rawResult = await Promise.resolve(gadget.execute(validatedParams));
7063
+ if (typeof rawResult === "string") {
7064
+ return {
7065
+ result: rawResult,
7066
+ validatedParams,
7067
+ cost: 0
7068
+ };
7069
+ }
6704
7070
  return {
6705
- result,
6706
- validatedParams
7071
+ result: rawResult.result,
7072
+ validatedParams,
7073
+ cost: rawResult.cost ?? 0
6707
7074
  };
6708
7075
  } catch (error) {
6709
7076
  return {
@@ -8012,6 +8379,10 @@ export {
8012
8379
  init_prompt_config,
8013
8380
  LLMMessageBuilder,
8014
8381
  init_messages,
8382
+ BreakLoopException,
8383
+ HumanInputException,
8384
+ AbortError,
8385
+ init_exceptions,
8015
8386
  createLogger,
8016
8387
  defaultLogger,
8017
8388
  init_logger,
@@ -8041,9 +8412,6 @@ export {
8041
8412
  collectEvents,
8042
8413
  collectText,
8043
8414
  init_event_handlers,
8044
- BreakLoopException,
8045
- HumanInputException,
8046
- init_exceptions,
8047
8415
  StreamParser,
8048
8416
  init_parser,
8049
8417
  GadgetExecutor,
@@ -8116,4 +8484,4 @@ export {
8116
8484
  MockPromptRecorder,
8117
8485
  waitFor
8118
8486
  };
8119
- //# sourceMappingURL=chunk-E52IO2NO.js.map
8487
+ //# sourceMappingURL=chunk-PDYVT3FI.js.map