llmist 1.7.0 → 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-E52IO2NO.js → chunk-LBHWVCZ2.js} +316 -53
- package/dist/chunk-LBHWVCZ2.js.map +1 -0
- package/dist/{chunk-JGORHSHC.js → chunk-LFSIEPAE.js} +10 -3
- package/dist/chunk-LFSIEPAE.js.map +1 -0
- package/dist/cli.cjs +326 -59
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +28 -15
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +310 -47
- 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-BMuFlQI1.d.cts → mock-stream-BQHut0lQ.d.cts} +575 -320
- package/dist/{mock-stream-BMuFlQI1.d.ts → mock-stream-BQHut0lQ.d.ts} +575 -320
- package/dist/testing/index.cjs +311 -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/cli.cjs
CHANGED
|
@@ -644,6 +644,44 @@ ${this.endPrefix}`
|
|
|
644
644
|
}
|
|
645
645
|
});
|
|
646
646
|
|
|
647
|
+
// src/gadgets/exceptions.ts
|
|
648
|
+
var BreakLoopException, HumanInputException, TimeoutException, AbortError;
|
|
649
|
+
var init_exceptions = __esm({
|
|
650
|
+
"src/gadgets/exceptions.ts"() {
|
|
651
|
+
"use strict";
|
|
652
|
+
BreakLoopException = class extends Error {
|
|
653
|
+
constructor(message) {
|
|
654
|
+
super(message ?? "Agent loop terminated by gadget");
|
|
655
|
+
this.name = "BreakLoopException";
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
HumanInputException = class extends Error {
|
|
659
|
+
question;
|
|
660
|
+
constructor(question) {
|
|
661
|
+
super(`Human input required: ${question}`);
|
|
662
|
+
this.name = "HumanInputException";
|
|
663
|
+
this.question = question;
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
TimeoutException = class extends Error {
|
|
667
|
+
timeoutMs;
|
|
668
|
+
gadgetName;
|
|
669
|
+
constructor(gadgetName, timeoutMs) {
|
|
670
|
+
super(`Gadget '${gadgetName}' execution exceeded timeout of ${timeoutMs}ms`);
|
|
671
|
+
this.name = "TimeoutException";
|
|
672
|
+
this.gadgetName = gadgetName;
|
|
673
|
+
this.timeoutMs = timeoutMs;
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
AbortError = class extends Error {
|
|
677
|
+
constructor(message) {
|
|
678
|
+
super(message || "Gadget execution was aborted");
|
|
679
|
+
this.name = "AbortError";
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
|
|
647
685
|
// src/logging/logger.ts
|
|
648
686
|
function parseLogLevel(value) {
|
|
649
687
|
if (!value) {
|
|
@@ -916,6 +954,7 @@ var init_gadget = __esm({
|
|
|
916
954
|
"src/gadgets/gadget.ts"() {
|
|
917
955
|
"use strict";
|
|
918
956
|
init_constants();
|
|
957
|
+
init_exceptions();
|
|
919
958
|
init_schema_to_json();
|
|
920
959
|
init_schema_validator();
|
|
921
960
|
BaseGadget = class {
|
|
@@ -945,6 +984,42 @@ var init_gadget = __esm({
|
|
|
945
984
|
* while maintaining runtime compatibility.
|
|
946
985
|
*/
|
|
947
986
|
examples;
|
|
987
|
+
/**
|
|
988
|
+
* Throws an AbortError if the execution has been aborted.
|
|
989
|
+
*
|
|
990
|
+
* Call this at key checkpoints in long-running gadgets to allow early exit
|
|
991
|
+
* when the gadget has been cancelled (e.g., due to timeout). This enables
|
|
992
|
+
* resource cleanup and prevents unnecessary work after cancellation.
|
|
993
|
+
*
|
|
994
|
+
* @param ctx - The execution context containing the abort signal
|
|
995
|
+
* @throws AbortError if ctx.signal.aborted is true
|
|
996
|
+
*
|
|
997
|
+
* @example
|
|
998
|
+
* ```typescript
|
|
999
|
+
* class DataProcessor extends Gadget({
|
|
1000
|
+
* description: 'Processes data in multiple steps',
|
|
1001
|
+
* schema: z.object({ items: z.array(z.string()) }),
|
|
1002
|
+
* }) {
|
|
1003
|
+
* async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {
|
|
1004
|
+
* const results: string[] = [];
|
|
1005
|
+
*
|
|
1006
|
+
* for (const item of params.items) {
|
|
1007
|
+
* // Check before each expensive operation
|
|
1008
|
+
* this.throwIfAborted(ctx);
|
|
1009
|
+
*
|
|
1010
|
+
* results.push(await this.processItem(item));
|
|
1011
|
+
* }
|
|
1012
|
+
*
|
|
1013
|
+
* return results.join(', ');
|
|
1014
|
+
* }
|
|
1015
|
+
* }
|
|
1016
|
+
* ```
|
|
1017
|
+
*/
|
|
1018
|
+
throwIfAborted(ctx) {
|
|
1019
|
+
if (ctx?.signal?.aborted) {
|
|
1020
|
+
throw new AbortError();
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
948
1023
|
/**
|
|
949
1024
|
* Auto-generated instruction text for the LLM.
|
|
950
1025
|
* Combines name, description, and parameter schema into a formatted instruction.
|
|
@@ -1012,8 +1087,8 @@ function createGadget(config) {
|
|
|
1012
1087
|
parameterSchema = config.schema;
|
|
1013
1088
|
timeoutMs = config.timeoutMs;
|
|
1014
1089
|
examples = config.examples;
|
|
1015
|
-
execute(params) {
|
|
1016
|
-
return config.execute(params);
|
|
1090
|
+
execute(params, ctx) {
|
|
1091
|
+
return config.execute(params, ctx);
|
|
1017
1092
|
}
|
|
1018
1093
|
}
|
|
1019
1094
|
return new DynamicGadget();
|
|
@@ -2319,6 +2394,162 @@ var init_block_params = __esm({
|
|
|
2319
2394
|
}
|
|
2320
2395
|
});
|
|
2321
2396
|
|
|
2397
|
+
// src/gadgets/cost-reporting-client.ts
|
|
2398
|
+
var CostReportingLLMistWrapper;
|
|
2399
|
+
var init_cost_reporting_client = __esm({
|
|
2400
|
+
"src/gadgets/cost-reporting-client.ts"() {
|
|
2401
|
+
"use strict";
|
|
2402
|
+
init_model_shortcuts();
|
|
2403
|
+
CostReportingLLMistWrapper = class {
|
|
2404
|
+
constructor(client, reportCost) {
|
|
2405
|
+
this.client = client;
|
|
2406
|
+
this.reportCost = reportCost;
|
|
2407
|
+
}
|
|
2408
|
+
/**
|
|
2409
|
+
* Access to model registry for cost estimation.
|
|
2410
|
+
*/
|
|
2411
|
+
get modelRegistry() {
|
|
2412
|
+
return this.client.modelRegistry;
|
|
2413
|
+
}
|
|
2414
|
+
/**
|
|
2415
|
+
* Quick completion with automatic cost reporting.
|
|
2416
|
+
*
|
|
2417
|
+
* Streams internally to track token usage, then reports the calculated cost.
|
|
2418
|
+
*
|
|
2419
|
+
* @param prompt - User prompt
|
|
2420
|
+
* @param options - Optional configuration (model, temperature, etc.)
|
|
2421
|
+
* @returns Complete text response
|
|
2422
|
+
*/
|
|
2423
|
+
async complete(prompt, options) {
|
|
2424
|
+
const model = resolveModel(options?.model ?? "haiku");
|
|
2425
|
+
let result = "";
|
|
2426
|
+
let inputTokens = 0;
|
|
2427
|
+
let outputTokens = 0;
|
|
2428
|
+
let cachedInputTokens = 0;
|
|
2429
|
+
let cacheCreationInputTokens = 0;
|
|
2430
|
+
const messages = [
|
|
2431
|
+
...options?.systemPrompt ? [{ role: "system", content: options.systemPrompt }] : [],
|
|
2432
|
+
{ role: "user", content: prompt }
|
|
2433
|
+
];
|
|
2434
|
+
for await (const chunk of this.client.stream({
|
|
2435
|
+
model,
|
|
2436
|
+
messages,
|
|
2437
|
+
temperature: options?.temperature,
|
|
2438
|
+
maxTokens: options?.maxTokens
|
|
2439
|
+
})) {
|
|
2440
|
+
result += chunk.text ?? "";
|
|
2441
|
+
if (chunk.usage) {
|
|
2442
|
+
inputTokens = chunk.usage.inputTokens;
|
|
2443
|
+
outputTokens = chunk.usage.outputTokens;
|
|
2444
|
+
cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
|
|
2445
|
+
cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
|
|
2449
|
+
return result;
|
|
2450
|
+
}
|
|
2451
|
+
/**
|
|
2452
|
+
* Quick streaming with automatic cost reporting when stream completes.
|
|
2453
|
+
*
|
|
2454
|
+
* Yields text chunks as they arrive, then reports cost in finally block.
|
|
2455
|
+
*
|
|
2456
|
+
* @param prompt - User prompt
|
|
2457
|
+
* @param options - Optional configuration (model, temperature, etc.)
|
|
2458
|
+
* @returns Async generator yielding text chunks
|
|
2459
|
+
*/
|
|
2460
|
+
async *streamText(prompt, options) {
|
|
2461
|
+
const model = resolveModel(options?.model ?? "haiku");
|
|
2462
|
+
let inputTokens = 0;
|
|
2463
|
+
let outputTokens = 0;
|
|
2464
|
+
let cachedInputTokens = 0;
|
|
2465
|
+
let cacheCreationInputTokens = 0;
|
|
2466
|
+
const messages = [
|
|
2467
|
+
...options?.systemPrompt ? [{ role: "system", content: options.systemPrompt }] : [],
|
|
2468
|
+
{ role: "user", content: prompt }
|
|
2469
|
+
];
|
|
2470
|
+
try {
|
|
2471
|
+
for await (const chunk of this.client.stream({
|
|
2472
|
+
model,
|
|
2473
|
+
messages,
|
|
2474
|
+
temperature: options?.temperature,
|
|
2475
|
+
maxTokens: options?.maxTokens
|
|
2476
|
+
})) {
|
|
2477
|
+
if (chunk.text) {
|
|
2478
|
+
yield chunk.text;
|
|
2479
|
+
}
|
|
2480
|
+
if (chunk.usage) {
|
|
2481
|
+
inputTokens = chunk.usage.inputTokens;
|
|
2482
|
+
outputTokens = chunk.usage.outputTokens;
|
|
2483
|
+
cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
|
|
2484
|
+
cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
} finally {
|
|
2488
|
+
this.reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
/**
|
|
2492
|
+
* Low-level stream access with automatic cost reporting.
|
|
2493
|
+
*
|
|
2494
|
+
* Returns a wrapped stream that reports costs when iteration completes.
|
|
2495
|
+
*
|
|
2496
|
+
* @param options - Full LLM generation options
|
|
2497
|
+
* @returns Wrapped LLM stream that auto-reports costs
|
|
2498
|
+
*/
|
|
2499
|
+
stream(options) {
|
|
2500
|
+
return this.createCostReportingStream(options);
|
|
2501
|
+
}
|
|
2502
|
+
/**
|
|
2503
|
+
* Creates a wrapped stream that tracks usage and reports costs on completion.
|
|
2504
|
+
*/
|
|
2505
|
+
createCostReportingStream(options) {
|
|
2506
|
+
const innerStream = this.client.stream(options);
|
|
2507
|
+
const reportCostFromUsage = this.reportCostFromUsage.bind(this);
|
|
2508
|
+
const model = options.model;
|
|
2509
|
+
async function* costReportingWrapper() {
|
|
2510
|
+
let inputTokens = 0;
|
|
2511
|
+
let outputTokens = 0;
|
|
2512
|
+
let cachedInputTokens = 0;
|
|
2513
|
+
let cacheCreationInputTokens = 0;
|
|
2514
|
+
try {
|
|
2515
|
+
for await (const chunk of innerStream) {
|
|
2516
|
+
if (chunk.usage) {
|
|
2517
|
+
inputTokens = chunk.usage.inputTokens;
|
|
2518
|
+
outputTokens = chunk.usage.outputTokens;
|
|
2519
|
+
cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;
|
|
2520
|
+
cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;
|
|
2521
|
+
}
|
|
2522
|
+
yield chunk;
|
|
2523
|
+
}
|
|
2524
|
+
} finally {
|
|
2525
|
+
if (inputTokens > 0 || outputTokens > 0) {
|
|
2526
|
+
reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens);
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
return costReportingWrapper();
|
|
2531
|
+
}
|
|
2532
|
+
/**
|
|
2533
|
+
* Calculates and reports cost from token usage.
|
|
2534
|
+
*/
|
|
2535
|
+
reportCostFromUsage(model, inputTokens, outputTokens, cachedInputTokens = 0, cacheCreationInputTokens = 0) {
|
|
2536
|
+
if (inputTokens === 0 && outputTokens === 0) return;
|
|
2537
|
+
const modelName = model.includes(":") ? model.split(":")[1] : model;
|
|
2538
|
+
const estimate = this.client.modelRegistry.estimateCost(
|
|
2539
|
+
modelName,
|
|
2540
|
+
inputTokens,
|
|
2541
|
+
outputTokens,
|
|
2542
|
+
cachedInputTokens,
|
|
2543
|
+
cacheCreationInputTokens
|
|
2544
|
+
);
|
|
2545
|
+
if (estimate && estimate.totalCost > 0) {
|
|
2546
|
+
this.reportCost(estimate.totalCost);
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
};
|
|
2550
|
+
}
|
|
2551
|
+
});
|
|
2552
|
+
|
|
2322
2553
|
// src/gadgets/error-formatter.ts
|
|
2323
2554
|
var GadgetErrorFormatter;
|
|
2324
2555
|
var init_error_formatter = __esm({
|
|
@@ -2402,38 +2633,6 @@ var init_error_formatter = __esm({
|
|
|
2402
2633
|
}
|
|
2403
2634
|
});
|
|
2404
2635
|
|
|
2405
|
-
// src/gadgets/exceptions.ts
|
|
2406
|
-
var BreakLoopException, HumanInputException, TimeoutException;
|
|
2407
|
-
var init_exceptions = __esm({
|
|
2408
|
-
"src/gadgets/exceptions.ts"() {
|
|
2409
|
-
"use strict";
|
|
2410
|
-
BreakLoopException = class extends Error {
|
|
2411
|
-
constructor(message) {
|
|
2412
|
-
super(message ?? "Agent loop terminated by gadget");
|
|
2413
|
-
this.name = "BreakLoopException";
|
|
2414
|
-
}
|
|
2415
|
-
};
|
|
2416
|
-
HumanInputException = class extends Error {
|
|
2417
|
-
question;
|
|
2418
|
-
constructor(question) {
|
|
2419
|
-
super(`Human input required: ${question}`);
|
|
2420
|
-
this.name = "HumanInputException";
|
|
2421
|
-
this.question = question;
|
|
2422
|
-
}
|
|
2423
|
-
};
|
|
2424
|
-
TimeoutException = class extends Error {
|
|
2425
|
-
timeoutMs;
|
|
2426
|
-
gadgetName;
|
|
2427
|
-
constructor(gadgetName, timeoutMs) {
|
|
2428
|
-
super(`Gadget '${gadgetName}' execution exceeded timeout of ${timeoutMs}ms`);
|
|
2429
|
-
this.name = "TimeoutException";
|
|
2430
|
-
this.gadgetName = gadgetName;
|
|
2431
|
-
this.timeoutMs = timeoutMs;
|
|
2432
|
-
}
|
|
2433
|
-
};
|
|
2434
|
-
}
|
|
2435
|
-
});
|
|
2436
|
-
|
|
2437
2636
|
// src/gadgets/parser.ts
|
|
2438
2637
|
function stripMarkdownFences(content) {
|
|
2439
2638
|
let cleaned = content.trim();
|
|
@@ -2619,14 +2818,16 @@ var init_executor = __esm({
|
|
|
2619
2818
|
init_constants();
|
|
2620
2819
|
init_logger();
|
|
2621
2820
|
init_block_params();
|
|
2821
|
+
init_cost_reporting_client();
|
|
2622
2822
|
init_error_formatter();
|
|
2623
2823
|
init_exceptions();
|
|
2624
2824
|
init_parser();
|
|
2625
2825
|
GadgetExecutor = class {
|
|
2626
|
-
constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions) {
|
|
2826
|
+
constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client) {
|
|
2627
2827
|
this.registry = registry;
|
|
2628
2828
|
this.onHumanInputRequired = onHumanInputRequired;
|
|
2629
2829
|
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
2830
|
+
this.client = client;
|
|
2630
2831
|
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
2631
2832
|
this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
|
|
2632
2833
|
this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
@@ -2636,14 +2837,27 @@ var init_executor = __esm({
|
|
|
2636
2837
|
argPrefix;
|
|
2637
2838
|
/**
|
|
2638
2839
|
* Creates a promise that rejects with a TimeoutException after the specified timeout.
|
|
2840
|
+
* Aborts the provided AbortController before rejecting, allowing gadgets to clean up.
|
|
2639
2841
|
*/
|
|
2640
|
-
createTimeoutPromise(gadgetName, timeoutMs) {
|
|
2842
|
+
createTimeoutPromise(gadgetName, timeoutMs, abortController) {
|
|
2641
2843
|
return new Promise((_, reject) => {
|
|
2642
2844
|
setTimeout(() => {
|
|
2643
|
-
|
|
2845
|
+
const timeoutError = new TimeoutException(gadgetName, timeoutMs);
|
|
2846
|
+
abortController.abort(timeoutError.message);
|
|
2847
|
+
reject(timeoutError);
|
|
2644
2848
|
}, timeoutMs);
|
|
2645
2849
|
});
|
|
2646
2850
|
}
|
|
2851
|
+
/**
|
|
2852
|
+
* Normalizes gadget execute result to consistent format.
|
|
2853
|
+
* Handles both string returns (backwards compat) and object returns with cost.
|
|
2854
|
+
*/
|
|
2855
|
+
normalizeExecuteResult(raw) {
|
|
2856
|
+
if (typeof raw === "string") {
|
|
2857
|
+
return { result: raw, cost: 0 };
|
|
2858
|
+
}
|
|
2859
|
+
return { result: raw.result, cost: raw.cost ?? 0 };
|
|
2860
|
+
}
|
|
2647
2861
|
// Execute a gadget call asynchronously
|
|
2648
2862
|
async execute(call) {
|
|
2649
2863
|
const startTime = Date.now();
|
|
@@ -2738,30 +2952,53 @@ var init_executor = __esm({
|
|
|
2738
2952
|
validatedParameters = schemaAwareParameters;
|
|
2739
2953
|
}
|
|
2740
2954
|
const timeoutMs = gadget.timeoutMs ?? this.defaultGadgetTimeoutMs;
|
|
2741
|
-
|
|
2955
|
+
const abortController = new AbortController();
|
|
2956
|
+
let callbackCost = 0;
|
|
2957
|
+
const reportCost = (amount) => {
|
|
2958
|
+
if (amount > 0) {
|
|
2959
|
+
callbackCost += amount;
|
|
2960
|
+
this.logger.debug("Gadget reported cost via callback", {
|
|
2961
|
+
gadgetName: call.gadgetName,
|
|
2962
|
+
amount,
|
|
2963
|
+
totalCallbackCost: callbackCost
|
|
2964
|
+
});
|
|
2965
|
+
}
|
|
2966
|
+
};
|
|
2967
|
+
const ctx = {
|
|
2968
|
+
reportCost,
|
|
2969
|
+
llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
|
|
2970
|
+
signal: abortController.signal
|
|
2971
|
+
};
|
|
2972
|
+
let rawResult;
|
|
2742
2973
|
if (timeoutMs && timeoutMs > 0) {
|
|
2743
2974
|
this.logger.debug("Executing gadget with timeout", {
|
|
2744
2975
|
gadgetName: call.gadgetName,
|
|
2745
2976
|
timeoutMs
|
|
2746
2977
|
});
|
|
2747
|
-
|
|
2748
|
-
Promise.resolve(gadget.execute(validatedParameters)),
|
|
2749
|
-
this.createTimeoutPromise(call.gadgetName, timeoutMs)
|
|
2978
|
+
rawResult = await Promise.race([
|
|
2979
|
+
Promise.resolve(gadget.execute(validatedParameters, ctx)),
|
|
2980
|
+
this.createTimeoutPromise(call.gadgetName, timeoutMs, abortController)
|
|
2750
2981
|
]);
|
|
2751
2982
|
} else {
|
|
2752
|
-
|
|
2983
|
+
rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
|
|
2753
2984
|
}
|
|
2985
|
+
const { result, cost: returnCost } = this.normalizeExecuteResult(rawResult);
|
|
2986
|
+
const totalCost = callbackCost + returnCost;
|
|
2754
2987
|
const executionTimeMs = Date.now() - startTime;
|
|
2755
2988
|
this.logger.info("Gadget executed successfully", {
|
|
2756
2989
|
gadgetName: call.gadgetName,
|
|
2757
2990
|
invocationId: call.invocationId,
|
|
2758
|
-
executionTimeMs
|
|
2991
|
+
executionTimeMs,
|
|
2992
|
+
cost: totalCost > 0 ? totalCost : void 0,
|
|
2993
|
+
callbackCost: callbackCost > 0 ? callbackCost : void 0,
|
|
2994
|
+
returnCost: returnCost > 0 ? returnCost : void 0
|
|
2759
2995
|
});
|
|
2760
2996
|
this.logger.debug("Gadget result", {
|
|
2761
2997
|
gadgetName: call.gadgetName,
|
|
2762
2998
|
invocationId: call.invocationId,
|
|
2763
2999
|
parameters: validatedParameters,
|
|
2764
3000
|
result,
|
|
3001
|
+
cost: totalCost,
|
|
2765
3002
|
executionTimeMs
|
|
2766
3003
|
});
|
|
2767
3004
|
return {
|
|
@@ -2769,7 +3006,8 @@ var init_executor = __esm({
|
|
|
2769
3006
|
invocationId: call.invocationId,
|
|
2770
3007
|
parameters: validatedParameters,
|
|
2771
3008
|
result,
|
|
2772
|
-
executionTimeMs
|
|
3009
|
+
executionTimeMs,
|
|
3010
|
+
cost: totalCost
|
|
2773
3011
|
};
|
|
2774
3012
|
} catch (error) {
|
|
2775
3013
|
if (error instanceof BreakLoopException) {
|
|
@@ -2800,6 +3038,19 @@ var init_executor = __esm({
|
|
|
2800
3038
|
executionTimeMs: Date.now() - startTime
|
|
2801
3039
|
};
|
|
2802
3040
|
}
|
|
3041
|
+
if (error instanceof AbortError) {
|
|
3042
|
+
this.logger.info("Gadget execution was aborted", {
|
|
3043
|
+
gadgetName: call.gadgetName,
|
|
3044
|
+
executionTimeMs: Date.now() - startTime
|
|
3045
|
+
});
|
|
3046
|
+
return {
|
|
3047
|
+
gadgetName: call.gadgetName,
|
|
3048
|
+
invocationId: call.invocationId,
|
|
3049
|
+
parameters: validatedParameters,
|
|
3050
|
+
error: error.message,
|
|
3051
|
+
executionTimeMs: Date.now() - startTime
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
2803
3054
|
if (error instanceof HumanInputException) {
|
|
2804
3055
|
this.logger.info("Gadget requested human input", {
|
|
2805
3056
|
gadgetName: call.gadgetName,
|
|
@@ -2926,7 +3177,8 @@ var init_stream_processor = __esm({
|
|
|
2926
3177
|
options.onHumanInputRequired,
|
|
2927
3178
|
this.logger.getSubLogger({ name: "executor" }),
|
|
2928
3179
|
options.defaultGadgetTimeoutMs,
|
|
2929
|
-
{ argPrefix: options.gadgetArgPrefix }
|
|
3180
|
+
{ argPrefix: options.gadgetArgPrefix },
|
|
3181
|
+
options.client
|
|
2930
3182
|
);
|
|
2931
3183
|
}
|
|
2932
3184
|
/**
|
|
@@ -3193,6 +3445,7 @@ var init_stream_processor = __esm({
|
|
|
3193
3445
|
error: result.error,
|
|
3194
3446
|
executionTimeMs: result.executionTimeMs,
|
|
3195
3447
|
breaksLoop: result.breaksLoop,
|
|
3448
|
+
cost: result.cost,
|
|
3196
3449
|
logger: this.logger
|
|
3197
3450
|
};
|
|
3198
3451
|
await this.hooks.observers.onGadgetExecutionComplete(context);
|
|
@@ -3569,7 +3822,8 @@ var init_agent = __esm({
|
|
|
3569
3822
|
onHumanInputRequired: this.onHumanInputRequired,
|
|
3570
3823
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
3571
3824
|
shouldContinueAfterError: this.shouldContinueAfterError,
|
|
3572
|
-
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs
|
|
3825
|
+
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
3826
|
+
client: this.client
|
|
3573
3827
|
});
|
|
3574
3828
|
const result = await processor.process(stream2);
|
|
3575
3829
|
for (const output of result.outputs) {
|
|
@@ -6671,7 +6925,7 @@ var import_commander2 = require("commander");
|
|
|
6671
6925
|
// package.json
|
|
6672
6926
|
var package_default = {
|
|
6673
6927
|
name: "llmist",
|
|
6674
|
-
version: "1.
|
|
6928
|
+
version: "1.7.0",
|
|
6675
6929
|
description: "Universal TypeScript LLM client with streaming-first agent framework. Works with any model - no structured outputs or native tool calling required. Implements its own flexible grammar for function calling.",
|
|
6676
6930
|
type: "module",
|
|
6677
6931
|
main: "dist/index.cjs",
|
|
@@ -7534,38 +7788,46 @@ error: ${message}`;
|
|
|
7534
7788
|
var import_zod8 = require("zod");
|
|
7535
7789
|
var runCommand = createGadget({
|
|
7536
7790
|
name: "RunCommand",
|
|
7537
|
-
description: "Execute a
|
|
7791
|
+
description: "Execute a command with arguments and return its output. Uses argv array to bypass shell - arguments are passed directly without interpretation. Returns stdout/stderr combined with exit status.",
|
|
7538
7792
|
schema: import_zod8.z.object({
|
|
7539
|
-
|
|
7793
|
+
argv: import_zod8.z.array(import_zod8.z.string()).describe("Command and arguments as array (e.g., ['git', 'commit', '-m', 'message'])"),
|
|
7540
7794
|
cwd: import_zod8.z.string().optional().describe("Working directory for the command (default: current directory)"),
|
|
7541
7795
|
timeout: import_zod8.z.number().default(3e4).describe("Timeout in milliseconds (default: 30000)")
|
|
7542
7796
|
}),
|
|
7543
7797
|
examples: [
|
|
7544
7798
|
{
|
|
7545
|
-
params: {
|
|
7799
|
+
params: { argv: ["ls", "-la"], timeout: 3e4 },
|
|
7546
7800
|
output: "status=0\n\ntotal 24\ndrwxr-xr-x 5 user staff 160 Nov 27 10:00 .\ndrwxr-xr-x 3 user staff 96 Nov 27 09:00 ..\n-rw-r--r-- 1 user staff 1024 Nov 27 10:00 package.json",
|
|
7547
7801
|
comment: "List directory contents with details"
|
|
7548
7802
|
},
|
|
7549
7803
|
{
|
|
7550
|
-
params: {
|
|
7804
|
+
params: { argv: ["echo", "Hello World"], timeout: 3e4 },
|
|
7551
7805
|
output: "status=0\n\nHello World",
|
|
7552
|
-
comment: "
|
|
7806
|
+
comment: "Echo without shell - argument passed directly"
|
|
7553
7807
|
},
|
|
7554
7808
|
{
|
|
7555
|
-
params: {
|
|
7809
|
+
params: { argv: ["cat", "nonexistent.txt"], timeout: 3e4 },
|
|
7556
7810
|
output: "status=1\n\ncat: nonexistent.txt: No such file or directory",
|
|
7557
7811
|
comment: "Command that fails returns non-zero status"
|
|
7558
7812
|
},
|
|
7559
7813
|
{
|
|
7560
|
-
params: {
|
|
7814
|
+
params: { argv: ["pwd"], cwd: "/tmp", timeout: 3e4 },
|
|
7561
7815
|
output: "status=0\n\n/tmp",
|
|
7562
7816
|
comment: "Execute command in a specific directory"
|
|
7817
|
+
},
|
|
7818
|
+
{
|
|
7819
|
+
params: { argv: ["gh", "pr", "review", "123", "--comment", "--body", "Review with `backticks` and 'quotes'"], timeout: 3e4 },
|
|
7820
|
+
output: "status=0\n\n(no output)",
|
|
7821
|
+
comment: "Complex arguments with special characters - no escaping needed"
|
|
7563
7822
|
}
|
|
7564
7823
|
],
|
|
7565
|
-
execute: async ({
|
|
7824
|
+
execute: async ({ argv, cwd, timeout }) => {
|
|
7566
7825
|
const workingDir = cwd ?? process.cwd();
|
|
7826
|
+
if (argv.length === 0) {
|
|
7827
|
+
return "status=1\n\nerror: argv array cannot be empty";
|
|
7828
|
+
}
|
|
7567
7829
|
try {
|
|
7568
|
-
const proc = Bun.spawn(
|
|
7830
|
+
const proc = Bun.spawn(argv, {
|
|
7569
7831
|
cwd: workingDir,
|
|
7570
7832
|
stdout: "pipe",
|
|
7571
7833
|
stderr: "pipe"
|
|
@@ -10473,9 +10735,11 @@ ${issues}`);
|
|
|
10473
10735
|
env.stderr.write(import_chalk7.default.dim("\nExecuting...\n"));
|
|
10474
10736
|
const startTime = Date.now();
|
|
10475
10737
|
let result;
|
|
10738
|
+
let cost;
|
|
10476
10739
|
try {
|
|
10740
|
+
let rawResult;
|
|
10477
10741
|
if (gadget.timeoutMs && gadget.timeoutMs > 0) {
|
|
10478
|
-
|
|
10742
|
+
rawResult = await Promise.race([
|
|
10479
10743
|
Promise.resolve(gadget.execute(params)),
|
|
10480
10744
|
new Promise(
|
|
10481
10745
|
(_, reject) => setTimeout(
|
|
@@ -10485,15 +10749,18 @@ ${issues}`);
|
|
|
10485
10749
|
)
|
|
10486
10750
|
]);
|
|
10487
10751
|
} else {
|
|
10488
|
-
|
|
10752
|
+
rawResult = await Promise.resolve(gadget.execute(params));
|
|
10489
10753
|
}
|
|
10754
|
+
result = typeof rawResult === "string" ? rawResult : rawResult.result;
|
|
10755
|
+
cost = typeof rawResult === "object" ? rawResult.cost : void 0;
|
|
10490
10756
|
} catch (error) {
|
|
10491
10757
|
const message = error instanceof Error ? error.message : String(error);
|
|
10492
10758
|
throw new Error(`Execution failed: ${message}`);
|
|
10493
10759
|
}
|
|
10494
10760
|
const elapsed = Date.now() - startTime;
|
|
10761
|
+
const costInfo = cost !== void 0 && cost > 0 ? ` (Cost: $${cost.toFixed(6)})` : "";
|
|
10495
10762
|
env.stderr.write(import_chalk7.default.green(`
|
|
10496
|
-
\u2713 Completed in ${elapsed}ms
|
|
10763
|
+
\u2713 Completed in ${elapsed}ms${costInfo}
|
|
10497
10764
|
|
|
10498
10765
|
`));
|
|
10499
10766
|
formatOutput(result, options, env.stdout);
|