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/{chunk-JGORHSHC.js → chunk-LSCCBXS7.js} +10 -3
- package/dist/chunk-LSCCBXS7.js.map +1 -0
- package/dist/{chunk-E52IO2NO.js → chunk-PDYVT3FI.js} +421 -53
- package/dist/chunk-PDYVT3FI.js.map +1 -0
- package/dist/cli.cjs +591 -154
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +188 -110
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +415 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +72 -13
- package/dist/index.d.ts +72 -13
- package/dist/index.js +4 -2
- package/dist/{mock-stream-BMuFlQI1.d.cts → mock-stream-HF7MBNhi.d.cts} +650 -319
- package/dist/{mock-stream-BMuFlQI1.d.ts → mock-stream-HF7MBNhi.d.ts} +650 -319
- package/dist/testing/index.cjs +416 -49
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +4 -2
- package/dist/testing/index.d.ts +4 -2
- package/dist/testing/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-E52IO2NO.js.map +0 -1
- package/dist/chunk-JGORHSHC.js.map +0 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|