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
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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-
|
|
8487
|
+
//# sourceMappingURL=chunk-PDYVT3FI.js.map
|