llmist 1.6.2 → 2.0.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-T3DIKQWU.js → chunk-LBHWVCZ2.js} +374 -55
- package/dist/chunk-LBHWVCZ2.js.map +1 -0
- package/dist/{chunk-TDRPJP2Q.js → chunk-LFSIEPAE.js} +10 -3
- package/dist/chunk-LFSIEPAE.js.map +1 -0
- package/dist/cli.cjs +384 -61
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +28 -15
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +368 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -13
- package/dist/index.d.ts +70 -13
- package/dist/index.js +4 -2
- package/dist/{mock-stream-Cc47j12U.d.cts → mock-stream-BQHut0lQ.d.cts} +595 -303
- package/dist/{mock-stream-Cc47j12U.d.ts → mock-stream-BQHut0lQ.d.ts} +595 -303
- package/dist/testing/index.cjs +369 -51
- 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-T3DIKQWU.js.map +0 -1
- package/dist/chunk-TDRPJP2Q.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,42 @@ 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
|
+
}
|
|
975
1050
|
/**
|
|
976
1051
|
* Auto-generated instruction text for the LLM.
|
|
977
1052
|
* Combines name, description, and parameter schema into a formatted instruction.
|
|
@@ -1039,8 +1114,8 @@ function createGadget(config) {
|
|
|
1039
1114
|
parameterSchema = config.schema;
|
|
1040
1115
|
timeoutMs = config.timeoutMs;
|
|
1041
1116
|
examples = config.examples;
|
|
1042
|
-
execute(params) {
|
|
1043
|
-
return config.execute(params);
|
|
1117
|
+
execute(params, ctx) {
|
|
1118
|
+
return config.execute(params, ctx);
|
|
1044
1119
|
}
|
|
1045
1120
|
}
|
|
1046
1121
|
return new DynamicGadget();
|
|
@@ -2376,6 +2451,162 @@ var init_block_params = __esm({
|
|
|
2376
2451
|
}
|
|
2377
2452
|
});
|
|
2378
2453
|
|
|
2454
|
+
// src/gadgets/cost-reporting-client.ts
|
|
2455
|
+
var CostReportingLLMistWrapper;
|
|
2456
|
+
var init_cost_reporting_client = __esm({
|
|
2457
|
+
"src/gadgets/cost-reporting-client.ts"() {
|
|
2458
|
+
"use strict";
|
|
2459
|
+
init_model_shortcuts();
|
|
2460
|
+
CostReportingLLMistWrapper = class {
|
|
2461
|
+
constructor(client, reportCost) {
|
|
2462
|
+
this.client = client;
|
|
2463
|
+
this.reportCost = reportCost;
|
|
2464
|
+
}
|
|
2465
|
+
/**
|
|
2466
|
+
* Access to model registry for cost estimation.
|
|
2467
|
+
*/
|
|
2468
|
+
get modelRegistry() {
|
|
2469
|
+
return this.client.modelRegistry;
|
|
2470
|
+
}
|
|
2471
|
+
/**
|
|
2472
|
+
* Quick completion with automatic cost reporting.
|
|
2473
|
+
*
|
|
2474
|
+
* Streams internally to track token usage, then reports the calculated cost.
|
|
2475
|
+
*
|
|
2476
|
+
* @param prompt - User prompt
|
|
2477
|
+
* @param options - Optional configuration (model, temperature, etc.)
|
|
2478
|
+
* @returns Complete text response
|
|
2479
|
+
*/
|
|
2480
|
+
async complete(prompt, options) {
|
|
2481
|
+
const model = resolveModel(options?.model ?? "haiku");
|
|
2482
|
+
let result = "";
|
|
2483
|
+
let inputTokens = 0;
|
|
2484
|
+
let outputTokens = 0;
|
|
2485
|
+
let cachedInputTokens = 0;
|
|
2486
|
+
let cacheCreationInputTokens = 0;
|
|
2487
|
+
const messages = [
|
|
2488
|
+
...options?.systemPrompt ? [{ role: "system", content: options.systemPrompt }] : [],
|
|
2489
|
+
{ role: "user", content: prompt }
|
|
2490
|
+
];
|
|
2491
|
+
for await (const chunk of this.client.stream({
|
|
2492
|
+
model,
|
|
2493
|
+
messages,
|
|
2494
|
+
temperature: options?.temperature,
|
|
2495
|
+
maxTokens: options?.maxTokens
|
|
2496
|
+
})) {
|
|
2497
|
+
result += chunk.text ?? "";
|
|
2498
|
+
if (chunk.usage) {
|
|
2499
|
+
inputTokens = chunk.usage.inputTokens;
|
|
2500
|
+
outputTokens = chunk.usage.outputTokens;
|
|
2501
|
+
cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
|
|
2502
|
+
cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
|
|
2506
|
+
return result;
|
|
2507
|
+
}
|
|
2508
|
+
/**
|
|
2509
|
+
* Quick streaming with automatic cost reporting when stream completes.
|
|
2510
|
+
*
|
|
2511
|
+
* Yields text chunks as they arrive, then reports cost in finally block.
|
|
2512
|
+
*
|
|
2513
|
+
* @param prompt - User prompt
|
|
2514
|
+
* @param options - Optional configuration (model, temperature, etc.)
|
|
2515
|
+
* @returns Async generator yielding text chunks
|
|
2516
|
+
*/
|
|
2517
|
+
async *streamText(prompt, options) {
|
|
2518
|
+
const model = resolveModel(options?.model ?? "haiku");
|
|
2519
|
+
let inputTokens = 0;
|
|
2520
|
+
let outputTokens = 0;
|
|
2521
|
+
let cachedInputTokens = 0;
|
|
2522
|
+
let cacheCreationInputTokens = 0;
|
|
2523
|
+
const messages = [
|
|
2524
|
+
...options?.systemPrompt ? [{ role: "system", content: options.systemPrompt }] : [],
|
|
2525
|
+
{ role: "user", content: prompt }
|
|
2526
|
+
];
|
|
2527
|
+
try {
|
|
2528
|
+
for await (const chunk of this.client.stream({
|
|
2529
|
+
model,
|
|
2530
|
+
messages,
|
|
2531
|
+
temperature: options?.temperature,
|
|
2532
|
+
maxTokens: options?.maxTokens
|
|
2533
|
+
})) {
|
|
2534
|
+
if (chunk.text) {
|
|
2535
|
+
yield chunk.text;
|
|
2536
|
+
}
|
|
2537
|
+
if (chunk.usage) {
|
|
2538
|
+
inputTokens = chunk.usage.inputTokens;
|
|
2539
|
+
outputTokens = chunk.usage.outputTokens;
|
|
2540
|
+
cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
|
|
2541
|
+
cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
} finally {
|
|
2545
|
+
this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
/**
|
|
2549
|
+
* Low-level stream access with automatic cost reporting.
|
|
2550
|
+
*
|
|
2551
|
+
* Returns a wrapped stream that reports costs when iteration completes.
|
|
2552
|
+
*
|
|
2553
|
+
* @param options - Full LLM generation options
|
|
2554
|
+
* @returns Wrapped LLM stream that auto-reports costs
|
|
2555
|
+
*/
|
|
2556
|
+
stream(options) {
|
|
2557
|
+
return this.createCostReportingStream(options);
|
|
2558
|
+
}
|
|
2559
|
+
/**
|
|
2560
|
+
* Creates a wrapped stream that tracks usage and reports costs on completion.
|
|
2561
|
+
*/
|
|
2562
|
+
createCostReportingStream(options) {
|
|
2563
|
+
const innerStream = this.client.stream(options);
|
|
2564
|
+
const reportCostFromUsage = this.reportCostFromUsage.bind(this);
|
|
2565
|
+
const model = options.model;
|
|
2566
|
+
async function* costReportingWrapper() {
|
|
2567
|
+
let inputTokens = 0;
|
|
2568
|
+
let outputTokens = 0;
|
|
2569
|
+
let cachedInputTokens = 0;
|
|
2570
|
+
let cacheCreationInputTokens = 0;
|
|
2571
|
+
try {
|
|
2572
|
+
for await (const chunk of innerStream) {
|
|
2573
|
+
if (chunk.usage) {
|
|
2574
|
+
inputTokens = chunk.usage.inputTokens;
|
|
2575
|
+
outputTokens = chunk.usage.outputTokens;
|
|
2576
|
+
cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
|
|
2577
|
+
cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
|
|
2578
|
+
}
|
|
2579
|
+
yield chunk;
|
|
2580
|
+
}
|
|
2581
|
+
} finally {
|
|
2582
|
+
if (inputTokens > 0 || outputTokens > 0) {
|
|
2583
|
+
reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
return costReportingWrapper();
|
|
2588
|
+
}
|
|
2589
|
+
/**
|
|
2590
|
+
* Calculates and reports cost from token usage.
|
|
2591
|
+
*/
|
|
2592
|
+
reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens = 0, cacheCreationInputTokens = 0) {
|
|
2593
|
+
if (inputTokens === 0 && outputTokens === 0) return;
|
|
2594
|
+
const modelName = model.includes(":") ? model.split(":")[1] : model;
|
|
2595
|
+
const estimate = this.client.modelRegistry.estimateCost(
|
|
2596
|
+
modelName,
|
|
2597
|
+
inputTokens,
|
|
2598
|
+
outputTokens,
|
|
2599
|
+
cachedInputTokens,
|
|
2600
|
+
cacheCreationInputTokens
|
|
2601
|
+
);
|
|
2602
|
+
if (estimate && estimate.totalCost > 0) {
|
|
2603
|
+
this.reportCost(estimate.totalCost);
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
};
|
|
2607
|
+
}
|
|
2608
|
+
});
|
|
2609
|
+
|
|
2379
2610
|
// src/gadgets/error-formatter.ts
|
|
2380
2611
|
var GadgetErrorFormatter;
|
|
2381
2612
|
var init_error_formatter = __esm({
|
|
@@ -2459,38 +2690,6 @@ var init_error_formatter = __esm({
|
|
|
2459
2690
|
}
|
|
2460
2691
|
});
|
|
2461
2692
|
|
|
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
2693
|
// src/gadgets/parser.ts
|
|
2495
2694
|
function stripMarkdownFences(content) {
|
|
2496
2695
|
let cleaned = content.trim();
|
|
@@ -2676,14 +2875,16 @@ var init_executor = __esm({
|
|
|
2676
2875
|
init_constants();
|
|
2677
2876
|
init_logger();
|
|
2678
2877
|
init_block_params();
|
|
2878
|
+
init_cost_reporting_client();
|
|
2679
2879
|
init_error_formatter();
|
|
2680
2880
|
init_exceptions();
|
|
2681
2881
|
init_parser();
|
|
2682
2882
|
GadgetExecutor = class {
|
|
2683
|
-
constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions) {
|
|
2883
|
+
constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client) {
|
|
2684
2884
|
this.registry = registry;
|
|
2685
2885
|
this.onHumanInputRequired = onHumanInputRequired;
|
|
2686
2886
|
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
2887
|
+
this.client = client;
|
|
2687
2888
|
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
2688
2889
|
this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
|
|
2689
2890
|
this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
@@ -2693,14 +2894,27 @@ var init_executor = __esm({
|
|
|
2693
2894
|
argPrefix;
|
|
2694
2895
|
/**
|
|
2695
2896
|
* Creates a promise that rejects with a TimeoutException after the specified timeout.
|
|
2897
|
+
* Aborts the provided AbortController before rejecting, allowing gadgets to clean up.
|
|
2696
2898
|
*/
|
|
2697
|
-
createTimeoutPromise(gadgetName, timeoutMs) {
|
|
2899
|
+
createTimeoutPromise(gadgetName, timeoutMs, abortController) {
|
|
2698
2900
|
return new Promise((_, reject) => {
|
|
2699
2901
|
setTimeout(() => {
|
|
2700
|
-
|
|
2902
|
+
const timeoutError = new TimeoutException(gadgetName, timeoutMs);
|
|
2903
|
+
abortController.abort(timeoutError.message);
|
|
2904
|
+
reject(timeoutError);
|
|
2701
2905
|
}, timeoutMs);
|
|
2702
2906
|
});
|
|
2703
2907
|
}
|
|
2908
|
+
/**
|
|
2909
|
+
* Normalizes gadget execute result to consistent format.
|
|
2910
|
+
* Handles both string returns (backwards compat) and object returns with cost.
|
|
2911
|
+
*/
|
|
2912
|
+
normalizeExecuteResult(raw) {
|
|
2913
|
+
if (typeof raw === "string") {
|
|
2914
|
+
return { result: raw, cost: 0 };
|
|
2915
|
+
}
|
|
2916
|
+
return { result: raw.result, cost: raw.cost ?? 0 };
|
|
2917
|
+
}
|
|
2704
2918
|
// Execute a gadget call asynchronously
|
|
2705
2919
|
async execute(call) {
|
|
2706
2920
|
const startTime = Date.now();
|
|
@@ -2795,30 +3009,53 @@ var init_executor = __esm({
|
|
|
2795
3009
|
validatedParameters = schemaAwareParameters;
|
|
2796
3010
|
}
|
|
2797
3011
|
const timeoutMs = gadget.timeoutMs ?? this.defaultGadgetTimeoutMs;
|
|
2798
|
-
|
|
3012
|
+
const abortController = new AbortController();
|
|
3013
|
+
let callbackCost = 0;
|
|
3014
|
+
const reportCost = (amount) => {
|
|
3015
|
+
if (amount > 0) {
|
|
3016
|
+
callbackCost += amount;
|
|
3017
|
+
this.logger.debug("Gadget reported cost via callback", {
|
|
3018
|
+
gadgetName: call.gadgetName,
|
|
3019
|
+
amount,
|
|
3020
|
+
totalCallbackCost: callbackCost
|
|
3021
|
+
});
|
|
3022
|
+
}
|
|
3023
|
+
};
|
|
3024
|
+
const ctx = {
|
|
3025
|
+
reportCost,
|
|
3026
|
+
llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
|
|
3027
|
+
signal: abortController.signal
|
|
3028
|
+
};
|
|
3029
|
+
let rawResult;
|
|
2799
3030
|
if (timeoutMs && timeoutMs > 0) {
|
|
2800
3031
|
this.logger.debug("Executing gadget with timeout", {
|
|
2801
3032
|
gadgetName: call.gadgetName,
|
|
2802
3033
|
timeoutMs
|
|
2803
3034
|
});
|
|
2804
|
-
|
|
2805
|
-
Promise.resolve(gadget.execute(validatedParameters)),
|
|
2806
|
-
this.createTimeoutPromise(call.gadgetName, timeoutMs)
|
|
3035
|
+
rawResult = await Promise.race([
|
|
3036
|
+
Promise.resolve(gadget.execute(validatedParameters, ctx)),
|
|
3037
|
+
this.createTimeoutPromise(call.gadgetName, timeoutMs, abortController)
|
|
2807
3038
|
]);
|
|
2808
3039
|
} else {
|
|
2809
|
-
|
|
3040
|
+
rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
|
|
2810
3041
|
}
|
|
3042
|
+
const { result, cost: returnCost } = this.normalizeExecuteResult(rawResult);
|
|
3043
|
+
const totalCost = callbackCost + returnCost;
|
|
2811
3044
|
const executionTimeMs = Date.now() - startTime;
|
|
2812
3045
|
this.logger.info("Gadget executed successfully", {
|
|
2813
3046
|
gadgetName: call.gadgetName,
|
|
2814
3047
|
invocationId: call.invocationId,
|
|
2815
|
-
executionTimeMs
|
|
3048
|
+
executionTimeMs,
|
|
3049
|
+
cost: totalCost > 0 ? totalCost : void 0,
|
|
3050
|
+
callbackCost: callbackCost > 0 ? callbackCost : void 0,
|
|
3051
|
+
returnCost: returnCost > 0 ? returnCost : void 0
|
|
2816
3052
|
});
|
|
2817
3053
|
this.logger.debug("Gadget result", {
|
|
2818
3054
|
gadgetName: call.gadgetName,
|
|
2819
3055
|
invocationId: call.invocationId,
|
|
2820
3056
|
parameters: validatedParameters,
|
|
2821
3057
|
result,
|
|
3058
|
+
cost: totalCost,
|
|
2822
3059
|
executionTimeMs
|
|
2823
3060
|
});
|
|
2824
3061
|
return {
|
|
@@ -2826,7 +3063,8 @@ var init_executor = __esm({
|
|
|
2826
3063
|
invocationId: call.invocationId,
|
|
2827
3064
|
parameters: validatedParameters,
|
|
2828
3065
|
result,
|
|
2829
|
-
executionTimeMs
|
|
3066
|
+
executionTimeMs,
|
|
3067
|
+
cost: totalCost
|
|
2830
3068
|
};
|
|
2831
3069
|
} catch (error) {
|
|
2832
3070
|
if (error instanceof BreakLoopException) {
|
|
@@ -2857,6 +3095,19 @@ var init_executor = __esm({
|
|
|
2857
3095
|
executionTimeMs: Date.now() - startTime
|
|
2858
3096
|
};
|
|
2859
3097
|
}
|
|
3098
|
+
if (error instanceof AbortError) {
|
|
3099
|
+
this.logger.info("Gadget execution was aborted", {
|
|
3100
|
+
gadgetName: call.gadgetName,
|
|
3101
|
+
executionTimeMs: Date.now() - startTime
|
|
3102
|
+
});
|
|
3103
|
+
return {
|
|
3104
|
+
gadgetName: call.gadgetName,
|
|
3105
|
+
invocationId: call.invocationId,
|
|
3106
|
+
parameters: validatedParameters,
|
|
3107
|
+
error: error.message,
|
|
3108
|
+
executionTimeMs: Date.now() - startTime
|
|
3109
|
+
};
|
|
3110
|
+
}
|
|
2860
3111
|
if (error instanceof HumanInputException) {
|
|
2861
3112
|
this.logger.info("Gadget requested human input", {
|
|
2862
3113
|
gadgetName: call.gadgetName,
|
|
@@ -2983,7 +3234,8 @@ var init_stream_processor = __esm({
|
|
|
2983
3234
|
options.onHumanInputRequired,
|
|
2984
3235
|
this.logger.getSubLogger({ name: "executor" }),
|
|
2985
3236
|
options.defaultGadgetTimeoutMs,
|
|
2986
|
-
{ argPrefix: options.gadgetArgPrefix }
|
|
3237
|
+
{ argPrefix: options.gadgetArgPrefix },
|
|
3238
|
+
options.client
|
|
2987
3239
|
);
|
|
2988
3240
|
}
|
|
2989
3241
|
/**
|
|
@@ -3250,6 +3502,7 @@ var init_stream_processor = __esm({
|
|
|
3250
3502
|
error: result.error,
|
|
3251
3503
|
executionTimeMs: result.executionTimeMs,
|
|
3252
3504
|
breaksLoop: result.breaksLoop,
|
|
3505
|
+
cost: result.cost,
|
|
3253
3506
|
logger: this.logger
|
|
3254
3507
|
};
|
|
3255
3508
|
await this.hooks.observers.onGadgetExecutionComplete(context);
|
|
@@ -3626,7 +3879,8 @@ var init_agent = __esm({
|
|
|
3626
3879
|
onHumanInputRequired: this.onHumanInputRequired,
|
|
3627
3880
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
3628
3881
|
shouldContinueAfterError: this.shouldContinueAfterError,
|
|
3629
|
-
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs
|
|
3882
|
+
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
3883
|
+
client: this.client
|
|
3630
3884
|
});
|
|
3631
3885
|
const result = await processor.process(stream2);
|
|
3632
3886
|
for (const output of result.outputs) {
|
|
@@ -5909,6 +6163,7 @@ var init_builder = __esm({
|
|
|
5909
6163
|
gadgetOutputLimitPercent;
|
|
5910
6164
|
compactionConfig;
|
|
5911
6165
|
signal;
|
|
6166
|
+
trailingMessage;
|
|
5912
6167
|
constructor(client) {
|
|
5913
6168
|
this.client = client;
|
|
5914
6169
|
}
|
|
@@ -6384,6 +6639,31 @@ var init_builder = __esm({
|
|
|
6384
6639
|
this.signal = signal;
|
|
6385
6640
|
return this;
|
|
6386
6641
|
}
|
|
6642
|
+
/**
|
|
6643
|
+
* Add an ephemeral trailing message that appears at the end of each LLM request.
|
|
6644
|
+
*
|
|
6645
|
+
* The message is NOT persisted to conversation history - it only appears in the
|
|
6646
|
+
* current LLM call. This is useful for injecting context-specific instructions
|
|
6647
|
+
* or reminders without polluting the conversation history.
|
|
6648
|
+
*
|
|
6649
|
+
* @param message - Static string or function that generates the message
|
|
6650
|
+
* @returns This builder for chaining
|
|
6651
|
+
*
|
|
6652
|
+
* @example
|
|
6653
|
+
* ```typescript
|
|
6654
|
+
* // Static message
|
|
6655
|
+
* .withTrailingMessage("Always respond in JSON format.")
|
|
6656
|
+
*
|
|
6657
|
+
* // Dynamic message based on iteration
|
|
6658
|
+
* .withTrailingMessage((ctx) =>
|
|
6659
|
+
* `[Iteration ${ctx.iteration}/${ctx.maxIterations}] Stay focused on the task.`
|
|
6660
|
+
* )
|
|
6661
|
+
* ```
|
|
6662
|
+
*/
|
|
6663
|
+
withTrailingMessage(message) {
|
|
6664
|
+
this.trailingMessage = message;
|
|
6665
|
+
return this;
|
|
6666
|
+
}
|
|
6387
6667
|
/**
|
|
6388
6668
|
* Add a synthetic gadget call to the conversation history.
|
|
6389
6669
|
*
|
|
@@ -6425,6 +6705,36 @@ ${endPrefix}`
|
|
|
6425
6705
|
});
|
|
6426
6706
|
return this;
|
|
6427
6707
|
}
|
|
6708
|
+
/**
|
|
6709
|
+
* Compose the final hooks, including trailing message if configured.
|
|
6710
|
+
*/
|
|
6711
|
+
composeHooks() {
|
|
6712
|
+
if (!this.trailingMessage) {
|
|
6713
|
+
return this.hooks;
|
|
6714
|
+
}
|
|
6715
|
+
const trailingMsg = this.trailingMessage;
|
|
6716
|
+
const existingBeforeLLMCall = this.hooks?.controllers?.beforeLLMCall;
|
|
6717
|
+
const trailingMessageController = async (ctx) => {
|
|
6718
|
+
const result = existingBeforeLLMCall ? await existingBeforeLLMCall(ctx) : { action: "proceed" };
|
|
6719
|
+
if (result.action === "skip") {
|
|
6720
|
+
return result;
|
|
6721
|
+
}
|
|
6722
|
+
const messages = [...result.modifiedOptions?.messages || ctx.options.messages];
|
|
6723
|
+
const content = typeof trailingMsg === "function" ? trailingMsg({ iteration: ctx.iteration, maxIterations: ctx.maxIterations }) : trailingMsg;
|
|
6724
|
+
messages.push({ role: "user", content });
|
|
6725
|
+
return {
|
|
6726
|
+
action: "proceed",
|
|
6727
|
+
modifiedOptions: { ...result.modifiedOptions, messages }
|
|
6728
|
+
};
|
|
6729
|
+
};
|
|
6730
|
+
return {
|
|
6731
|
+
...this.hooks,
|
|
6732
|
+
controllers: {
|
|
6733
|
+
...this.hooks?.controllers,
|
|
6734
|
+
beforeLLMCall: trailingMessageController
|
|
6735
|
+
}
|
|
6736
|
+
};
|
|
6737
|
+
}
|
|
6428
6738
|
/**
|
|
6429
6739
|
* Format parameters as block format with JSON Pointer paths.
|
|
6430
6740
|
*/
|
|
@@ -6486,7 +6796,7 @@ ${endPrefix}`
|
|
|
6486
6796
|
maxIterations: this.maxIterations,
|
|
6487
6797
|
temperature: this.temperature,
|
|
6488
6798
|
logger: this.logger,
|
|
6489
|
-
hooks: this.
|
|
6799
|
+
hooks: this.composeHooks(),
|
|
6490
6800
|
promptConfig: this.promptConfig,
|
|
6491
6801
|
initialMessages: this.initialMessages,
|
|
6492
6802
|
onHumanInputRequired: this.onHumanInputRequired,
|
|
@@ -6590,7 +6900,7 @@ ${endPrefix}`
|
|
|
6590
6900
|
maxIterations: this.maxIterations,
|
|
6591
6901
|
temperature: this.temperature,
|
|
6592
6902
|
logger: this.logger,
|
|
6593
|
-
hooks: this.
|
|
6903
|
+
hooks: this.composeHooks(),
|
|
6594
6904
|
promptConfig: this.promptConfig,
|
|
6595
6905
|
initialMessages: this.initialMessages,
|
|
6596
6906
|
onHumanInputRequired: this.onHumanInputRequired,
|
|
@@ -6616,6 +6926,7 @@ ${endPrefix}`
|
|
|
6616
6926
|
// src/index.ts
|
|
6617
6927
|
var index_exports = {};
|
|
6618
6928
|
__export(index_exports, {
|
|
6929
|
+
AbortError: () => AbortError,
|
|
6619
6930
|
AgentBuilder: () => AgentBuilder,
|
|
6620
6931
|
AnthropicMessagesProvider: () => AnthropicMessagesProvider,
|
|
6621
6932
|
BaseGadget: () => BaseGadget,
|
|
@@ -7053,6 +7364,7 @@ var HookPresets = class _HookPresets {
|
|
|
7053
7364
|
let totalInputTokens = 0;
|
|
7054
7365
|
let totalOutputTokens = 0;
|
|
7055
7366
|
let totalCost = 0;
|
|
7367
|
+
let totalGadgetCost = 0;
|
|
7056
7368
|
const startTime = Date.now();
|
|
7057
7369
|
return {
|
|
7058
7370
|
observers: {
|
|
@@ -7090,7 +7402,7 @@ var HookPresets = class _HookPresets {
|
|
|
7090
7402
|
totalInputTokens,
|
|
7091
7403
|
totalOutputTokens,
|
|
7092
7404
|
totalTokens: totalInputTokens + totalOutputTokens,
|
|
7093
|
-
totalCost,
|
|
7405
|
+
totalCost: totalCost + totalGadgetCost,
|
|
7094
7406
|
elapsedSeconds: Number(((Date.now() - startTime) / 1e3).toFixed(1))
|
|
7095
7407
|
};
|
|
7096
7408
|
if (onProgress) {
|
|
@@ -7103,6 +7415,12 @@ var HookPresets = class _HookPresets {
|
|
|
7103
7415
|
`\u{1F4CA} Progress: Iteration #${stats.currentIteration} | ${formattedTokens} tokens | ${formattedCost} | ${stats.elapsedSeconds}s`
|
|
7104
7416
|
);
|
|
7105
7417
|
}
|
|
7418
|
+
},
|
|
7419
|
+
// Track gadget execution costs
|
|
7420
|
+
onGadgetExecutionComplete: async (ctx) => {
|
|
7421
|
+
if (ctx.cost && ctx.cost > 0) {
|
|
7422
|
+
totalGadgetCost += ctx.cost;
|
|
7423
|
+
}
|
|
7106
7424
|
}
|
|
7107
7425
|
}
|
|
7108
7426
|
};
|
|
@@ -8346,6 +8664,7 @@ init_gadget();
|
|
|
8346
8664
|
var import_node_stream = require("stream");
|
|
8347
8665
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8348
8666
|
0 && (module.exports = {
|
|
8667
|
+
AbortError,
|
|
8349
8668
|
AgentBuilder,
|
|
8350
8669
|
AnthropicMessagesProvider,
|
|
8351
8670
|
BaseGadget,
|