llmist 0.3.1 → 0.4.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/cli.cjs +144 -111
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +144 -111
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +183 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +210 -3
- package/dist/index.d.ts +210 -3
- package/dist/index.js +183 -0
- package/dist/index.js.map +1 -1
- package/dist/{mock-stream-C2sBQlvc.d.cts → mock-stream-C0vOqI3L.d.cts} +1 -1
- package/dist/{mock-stream-C2sBQlvc.d.ts → mock-stream-C0vOqI3L.d.ts} +1 -1
- package/dist/testing/index.d.cts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -4281,7 +4281,8 @@ var OPTION_FLAGS = {
|
|
|
4281
4281
|
parameterFormat: "--parameter-format <format>",
|
|
4282
4282
|
logLevel: "--log-level <level>",
|
|
4283
4283
|
logFile: "--log-file <path>",
|
|
4284
|
-
noBuiltins: "--no-builtins"
|
|
4284
|
+
noBuiltins: "--no-builtins",
|
|
4285
|
+
noBuiltinInteraction: "--no-builtin-interaction"
|
|
4285
4286
|
};
|
|
4286
4287
|
var OPTION_DESCRIPTIONS = {
|
|
4287
4288
|
model: "Model identifier, e.g. openai:gpt-5-nano or anthropic:claude-sonnet-4-5.",
|
|
@@ -4293,7 +4294,8 @@ var OPTION_DESCRIPTIONS = {
|
|
|
4293
4294
|
parameterFormat: "Format for gadget parameter schemas: 'json', 'yaml', or 'auto'.",
|
|
4294
4295
|
logLevel: "Log level: silly, trace, debug, info, warn, error, fatal.",
|
|
4295
4296
|
logFile: "Path to log file. When set, logs are written to file instead of stderr.",
|
|
4296
|
-
noBuiltins: "Disable built-in gadgets (AskUser, TellUser)."
|
|
4297
|
+
noBuiltins: "Disable built-in gadgets (AskUser, TellUser).",
|
|
4298
|
+
noBuiltinInteraction: "Disable interactive gadgets (AskUser) while keeping TellUser."
|
|
4297
4299
|
};
|
|
4298
4300
|
var SUMMARY_PREFIX = "[llmist]";
|
|
4299
4301
|
|
|
@@ -4303,7 +4305,7 @@ var import_commander3 = require("commander");
|
|
|
4303
4305
|
// package.json
|
|
4304
4306
|
var package_default = {
|
|
4305
4307
|
name: "llmist",
|
|
4306
|
-
version: "0.3.
|
|
4308
|
+
version: "0.3.1",
|
|
4307
4309
|
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.",
|
|
4308
4310
|
type: "module",
|
|
4309
4311
|
main: "dist/index.cjs",
|
|
@@ -4412,7 +4414,6 @@ var package_default = {
|
|
|
4412
4414
|
|
|
4413
4415
|
// src/cli/agent-command.ts
|
|
4414
4416
|
var import_promises = require("readline/promises");
|
|
4415
|
-
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
4416
4417
|
var import_commander2 = require("commander");
|
|
4417
4418
|
init_builder();
|
|
4418
4419
|
init_registry();
|
|
@@ -4706,9 +4707,67 @@ async function loadGadgets(specifiers, cwd, importer = (specifier) => import(spe
|
|
|
4706
4707
|
}
|
|
4707
4708
|
|
|
4708
4709
|
// src/cli/utils.ts
|
|
4709
|
-
var
|
|
4710
|
+
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
4710
4711
|
var import_commander = require("commander");
|
|
4711
4712
|
init_constants2();
|
|
4713
|
+
|
|
4714
|
+
// src/cli/ui/formatters.ts
|
|
4715
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
4716
|
+
function formatTokens(tokens) {
|
|
4717
|
+
return tokens >= 1e3 ? `${(tokens / 1e3).toFixed(1)}k` : `${tokens}`;
|
|
4718
|
+
}
|
|
4719
|
+
function formatCost(cost) {
|
|
4720
|
+
if (cost < 1e-3) {
|
|
4721
|
+
return cost.toFixed(5);
|
|
4722
|
+
}
|
|
4723
|
+
if (cost < 0.01) {
|
|
4724
|
+
return cost.toFixed(4);
|
|
4725
|
+
}
|
|
4726
|
+
if (cost < 1) {
|
|
4727
|
+
return cost.toFixed(3);
|
|
4728
|
+
}
|
|
4729
|
+
return cost.toFixed(2);
|
|
4730
|
+
}
|
|
4731
|
+
function renderSummary(metadata) {
|
|
4732
|
+
const parts = [];
|
|
4733
|
+
if (metadata.iterations !== void 0) {
|
|
4734
|
+
parts.push(import_chalk.default.cyan(`#${metadata.iterations}`));
|
|
4735
|
+
}
|
|
4736
|
+
if (metadata.usage) {
|
|
4737
|
+
const { inputTokens, outputTokens } = metadata.usage;
|
|
4738
|
+
parts.push(import_chalk.default.dim("\u2191") + import_chalk.default.yellow(` ${formatTokens(inputTokens)}`));
|
|
4739
|
+
parts.push(import_chalk.default.dim("\u2193") + import_chalk.default.green(` ${formatTokens(outputTokens)}`));
|
|
4740
|
+
}
|
|
4741
|
+
if (metadata.elapsedSeconds !== void 0 && metadata.elapsedSeconds > 0) {
|
|
4742
|
+
parts.push(import_chalk.default.dim(`${metadata.elapsedSeconds}s`));
|
|
4743
|
+
}
|
|
4744
|
+
if (metadata.cost !== void 0 && metadata.cost > 0) {
|
|
4745
|
+
parts.push(import_chalk.default.cyan(`$${formatCost(metadata.cost)}`));
|
|
4746
|
+
}
|
|
4747
|
+
if (metadata.finishReason) {
|
|
4748
|
+
parts.push(import_chalk.default.dim(metadata.finishReason));
|
|
4749
|
+
}
|
|
4750
|
+
if (parts.length === 0) {
|
|
4751
|
+
return null;
|
|
4752
|
+
}
|
|
4753
|
+
return parts.join(import_chalk.default.dim(" | "));
|
|
4754
|
+
}
|
|
4755
|
+
function formatGadgetSummary(result) {
|
|
4756
|
+
const gadgetLabel = import_chalk.default.magenta.bold(result.gadgetName);
|
|
4757
|
+
const timeLabel = import_chalk.default.dim(`${Math.round(result.executionTimeMs)}ms`);
|
|
4758
|
+
if (result.error) {
|
|
4759
|
+
return `${import_chalk.default.red("\u2717")} ${gadgetLabel} ${import_chalk.default.red("error:")} ${result.error} ${timeLabel}`;
|
|
4760
|
+
}
|
|
4761
|
+
if (result.breaksLoop) {
|
|
4762
|
+
return `${import_chalk.default.yellow("\u23F9")} ${gadgetLabel} ${import_chalk.default.yellow("finished:")} ${result.result} ${timeLabel}`;
|
|
4763
|
+
}
|
|
4764
|
+
const maxLen = 80;
|
|
4765
|
+
const shouldTruncate = result.gadgetName !== "TellUser";
|
|
4766
|
+
const resultText = result.result ? shouldTruncate && result.result.length > maxLen ? `${result.result.slice(0, maxLen)}...` : result.result : "";
|
|
4767
|
+
return `${import_chalk.default.green("\u2713")} ${gadgetLabel} ${import_chalk.default.dim("\u2192")} ${resultText} ${timeLabel}`;
|
|
4768
|
+
}
|
|
4769
|
+
|
|
4770
|
+
// src/cli/utils.ts
|
|
4712
4771
|
function createNumericParser({
|
|
4713
4772
|
label,
|
|
4714
4773
|
integer = false,
|
|
@@ -4791,15 +4850,20 @@ var StreamProgress = class {
|
|
|
4791
4850
|
totalTokens = 0;
|
|
4792
4851
|
totalCost = 0;
|
|
4793
4852
|
iterations = 0;
|
|
4853
|
+
currentIteration = 0;
|
|
4794
4854
|
/**
|
|
4795
4855
|
* Starts a new LLM call. Switches to streaming mode.
|
|
4796
4856
|
* @param model - Model name being used
|
|
4797
|
-
* @param estimatedInputTokens -
|
|
4857
|
+
* @param estimatedInputTokens - Initial input token count. Should come from
|
|
4858
|
+
* client.countTokens() for accuracy (provider-specific counting), not
|
|
4859
|
+
* character-based estimation. Will be updated with provider-returned counts
|
|
4860
|
+
* via setInputTokens() during streaming if available.
|
|
4798
4861
|
*/
|
|
4799
4862
|
startCall(model, estimatedInputTokens) {
|
|
4800
4863
|
this.mode = "streaming";
|
|
4801
4864
|
this.model = model;
|
|
4802
4865
|
this.callStartTime = Date.now();
|
|
4866
|
+
this.currentIteration++;
|
|
4803
4867
|
this.callInputTokens = estimatedInputTokens ?? 0;
|
|
4804
4868
|
this.callInputTokensEstimated = true;
|
|
4805
4869
|
this.callOutputTokens = 0;
|
|
@@ -4836,8 +4900,10 @@ var StreamProgress = class {
|
|
|
4836
4900
|
}
|
|
4837
4901
|
/**
|
|
4838
4902
|
* Sets the input token count for current call (from stream metadata).
|
|
4839
|
-
* @param tokens - Token count
|
|
4840
|
-
* @param estimated - If true,
|
|
4903
|
+
* @param tokens - Token count from provider or client.countTokens()
|
|
4904
|
+
* @param estimated - If true, this is a fallback estimate (character-based).
|
|
4905
|
+
* If false, this is an accurate count from the provider API or client.countTokens().
|
|
4906
|
+
* Display shows ~ prefix only when estimated=true.
|
|
4841
4907
|
*/
|
|
4842
4908
|
setInputTokens(tokens, estimated = false) {
|
|
4843
4909
|
if (estimated && !this.callInputTokensEstimated) {
|
|
@@ -4848,8 +4914,10 @@ var StreamProgress = class {
|
|
|
4848
4914
|
}
|
|
4849
4915
|
/**
|
|
4850
4916
|
* Sets the output token count for current call (from stream metadata).
|
|
4851
|
-
* @param tokens - Token count
|
|
4852
|
-
* @param estimated - If true,
|
|
4917
|
+
* @param tokens - Token count from provider streaming response
|
|
4918
|
+
* @param estimated - If true, this is a fallback estimate (character-based).
|
|
4919
|
+
* If false, this is an accurate count from the provider's streaming metadata.
|
|
4920
|
+
* Display shows ~ prefix only when estimated=true.
|
|
4853
4921
|
*/
|
|
4854
4922
|
setOutputTokens(tokens, estimated = false) {
|
|
4855
4923
|
if (estimated && !this.callOutputTokensEstimated) {
|
|
@@ -4858,6 +4926,14 @@ var StreamProgress = class {
|
|
|
4858
4926
|
this.callOutputTokens = tokens;
|
|
4859
4927
|
this.callOutputTokensEstimated = estimated;
|
|
4860
4928
|
}
|
|
4929
|
+
/**
|
|
4930
|
+
* Get total elapsed time in seconds since the first call started.
|
|
4931
|
+
* @returns Elapsed time in seconds with 1 decimal place
|
|
4932
|
+
*/
|
|
4933
|
+
getTotalElapsedSeconds() {
|
|
4934
|
+
if (this.totalStartTime === 0) return 0;
|
|
4935
|
+
return Number(((Date.now() - this.totalStartTime) / 1e3).toFixed(1));
|
|
4936
|
+
}
|
|
4861
4937
|
/**
|
|
4862
4938
|
* Starts the progress indicator animation after a brief delay.
|
|
4863
4939
|
*/
|
|
@@ -4892,40 +4968,38 @@ var StreamProgress = class {
|
|
|
4892
4968
|
const elapsed = ((Date.now() - this.callStartTime) / 1e3).toFixed(1);
|
|
4893
4969
|
const outTokens = this.callOutputTokensEstimated ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN) : this.callOutputTokens;
|
|
4894
4970
|
const parts = [];
|
|
4895
|
-
|
|
4896
|
-
parts.push(import_chalk.default.cyan(this.model));
|
|
4897
|
-
}
|
|
4971
|
+
parts.push(import_chalk2.default.cyan(`#${this.currentIteration}`));
|
|
4898
4972
|
if (this.callInputTokens > 0) {
|
|
4899
4973
|
const prefix = this.callInputTokensEstimated ? "~" : "";
|
|
4900
|
-
parts.push(
|
|
4974
|
+
parts.push(import_chalk2.default.dim("\u2191") + import_chalk2.default.yellow(` ${prefix}${formatTokens(this.callInputTokens)}`));
|
|
4901
4975
|
}
|
|
4902
4976
|
if (this.isStreaming || outTokens > 0) {
|
|
4903
4977
|
const prefix = this.callOutputTokensEstimated ? "~" : "";
|
|
4904
|
-
parts.push(
|
|
4978
|
+
parts.push(import_chalk2.default.dim("\u2193") + import_chalk2.default.green(` ${prefix}${formatTokens(outTokens)}`));
|
|
4905
4979
|
}
|
|
4980
|
+
parts.push(import_chalk2.default.dim(`${elapsed}s`));
|
|
4906
4981
|
if (this.totalCost > 0) {
|
|
4907
|
-
parts.push(
|
|
4982
|
+
parts.push(import_chalk2.default.cyan(`$${formatCost(this.totalCost)}`));
|
|
4908
4983
|
}
|
|
4909
|
-
parts.
|
|
4910
|
-
this.target.write(`\r${import_chalk.default.cyan(spinner)} ${parts.join(import_chalk.default.dim(" | "))}`);
|
|
4984
|
+
this.target.write(`\r${import_chalk2.default.cyan(spinner)} ${parts.join(import_chalk2.default.dim(" | "))}`);
|
|
4911
4985
|
}
|
|
4912
4986
|
renderCumulativeMode(spinner) {
|
|
4913
4987
|
const elapsed = ((Date.now() - this.totalStartTime) / 1e3).toFixed(1);
|
|
4914
4988
|
const parts = [];
|
|
4915
4989
|
if (this.model) {
|
|
4916
|
-
parts.push(
|
|
4990
|
+
parts.push(import_chalk2.default.cyan(this.model));
|
|
4917
4991
|
}
|
|
4918
4992
|
if (this.totalTokens > 0) {
|
|
4919
|
-
parts.push(
|
|
4993
|
+
parts.push(import_chalk2.default.dim("total:") + import_chalk2.default.magenta(` ${this.totalTokens}`));
|
|
4920
4994
|
}
|
|
4921
4995
|
if (this.iterations > 0) {
|
|
4922
|
-
parts.push(
|
|
4996
|
+
parts.push(import_chalk2.default.dim("iter:") + import_chalk2.default.blue(` ${this.iterations}`));
|
|
4923
4997
|
}
|
|
4924
4998
|
if (this.totalCost > 0) {
|
|
4925
|
-
parts.push(
|
|
4999
|
+
parts.push(import_chalk2.default.dim("cost:") + import_chalk2.default.cyan(` $${formatCost(this.totalCost)}`));
|
|
4926
5000
|
}
|
|
4927
|
-
parts.push(
|
|
4928
|
-
this.target.write(`\r${
|
|
5001
|
+
parts.push(import_chalk2.default.dim(`${elapsed}s`));
|
|
5002
|
+
this.target.write(`\r${import_chalk2.default.cyan(spinner)} ${parts.join(import_chalk2.default.dim(" | "))}`);
|
|
4929
5003
|
}
|
|
4930
5004
|
/**
|
|
4931
5005
|
* Pauses the progress indicator and clears the line.
|
|
@@ -4973,49 +5047,28 @@ var StreamProgress = class {
|
|
|
4973
5047
|
if (this.callInputTokens > 0) {
|
|
4974
5048
|
const prefix = this.callInputTokensEstimated ? "~" : "";
|
|
4975
5049
|
parts.push(
|
|
4976
|
-
|
|
5050
|
+
import_chalk2.default.dim("\u2191") + import_chalk2.default.yellow(` ${prefix}${formatTokens(this.callInputTokens)}`)
|
|
4977
5051
|
);
|
|
4978
5052
|
}
|
|
4979
5053
|
if (outTokens > 0) {
|
|
4980
5054
|
const prefix = outEstimated ? "~" : "";
|
|
4981
|
-
parts.push(
|
|
5055
|
+
parts.push(import_chalk2.default.dim("\u2193") + import_chalk2.default.green(` ${prefix}${formatTokens(outTokens)}`));
|
|
4982
5056
|
}
|
|
4983
|
-
parts.push(
|
|
5057
|
+
parts.push(import_chalk2.default.dim(`${elapsed}s`));
|
|
4984
5058
|
} else {
|
|
4985
5059
|
const elapsed = Math.round((Date.now() - this.totalStartTime) / 1e3);
|
|
4986
5060
|
if (this.totalTokens > 0) {
|
|
4987
|
-
parts.push(
|
|
5061
|
+
parts.push(import_chalk2.default.magenta(formatTokens(this.totalTokens)));
|
|
4988
5062
|
}
|
|
4989
5063
|
if (this.iterations > 0) {
|
|
4990
|
-
parts.push(
|
|
5064
|
+
parts.push(import_chalk2.default.blue(`i${this.iterations}`));
|
|
4991
5065
|
}
|
|
4992
5066
|
if (this.totalCost > 0) {
|
|
4993
|
-
parts.push(
|
|
5067
|
+
parts.push(import_chalk2.default.cyan(`$${formatCost(this.totalCost)}`));
|
|
4994
5068
|
}
|
|
4995
|
-
parts.push(
|
|
4996
|
-
}
|
|
4997
|
-
return `${parts.join(import_chalk.default.dim(" \u2502 "))} ${import_chalk.default.green(">")} `;
|
|
4998
|
-
}
|
|
4999
|
-
/**
|
|
5000
|
-
* Formats token count compactly (3625 -> "3.6k").
|
|
5001
|
-
*/
|
|
5002
|
-
formatTokens(tokens) {
|
|
5003
|
-
return tokens >= 1e3 ? `${(tokens / 1e3).toFixed(1)}k` : `${tokens}`;
|
|
5004
|
-
}
|
|
5005
|
-
/**
|
|
5006
|
-
* Formats cost compactly (0.0001234 -> "0.00012", 0.1234 -> "0.12", 1.234 -> "1.23").
|
|
5007
|
-
*/
|
|
5008
|
-
formatCost(cost) {
|
|
5009
|
-
if (cost < 1e-3) {
|
|
5010
|
-
return cost.toFixed(5);
|
|
5011
|
-
}
|
|
5012
|
-
if (cost < 0.01) {
|
|
5013
|
-
return cost.toFixed(4);
|
|
5014
|
-
}
|
|
5015
|
-
if (cost < 1) {
|
|
5016
|
-
return cost.toFixed(3);
|
|
5069
|
+
parts.push(import_chalk2.default.dim(`${elapsed}s`));
|
|
5017
5070
|
}
|
|
5018
|
-
return
|
|
5071
|
+
return `${parts.join(import_chalk2.default.dim(" | "))} ${import_chalk2.default.green(">")} `;
|
|
5019
5072
|
}
|
|
5020
5073
|
};
|
|
5021
5074
|
async function readStream(stream2) {
|
|
@@ -5045,44 +5098,12 @@ async function resolvePrompt(promptArg, env) {
|
|
|
5045
5098
|
}
|
|
5046
5099
|
return pipedInput;
|
|
5047
5100
|
}
|
|
5048
|
-
function renderSummary(metadata) {
|
|
5049
|
-
const parts = [];
|
|
5050
|
-
if (metadata.iterations !== void 0) {
|
|
5051
|
-
parts.push(import_chalk.default.dim(`iterations: ${metadata.iterations}`));
|
|
5052
|
-
}
|
|
5053
|
-
if (metadata.finishReason) {
|
|
5054
|
-
parts.push(import_chalk.default.dim(`finish: ${metadata.finishReason}`));
|
|
5055
|
-
}
|
|
5056
|
-
if (metadata.usage) {
|
|
5057
|
-
const { inputTokens, outputTokens, totalTokens } = metadata.usage;
|
|
5058
|
-
parts.push(
|
|
5059
|
-
import_chalk.default.dim(`tokens: `) + import_chalk.default.cyan(`${totalTokens}`) + import_chalk.default.dim(` (in: ${inputTokens}, out: ${outputTokens})`)
|
|
5060
|
-
);
|
|
5061
|
-
}
|
|
5062
|
-
if (metadata.cost !== void 0 && metadata.cost > 0) {
|
|
5063
|
-
let formattedCost;
|
|
5064
|
-
if (metadata.cost < 1e-3) {
|
|
5065
|
-
formattedCost = metadata.cost.toFixed(5);
|
|
5066
|
-
} else if (metadata.cost < 0.01) {
|
|
5067
|
-
formattedCost = metadata.cost.toFixed(4);
|
|
5068
|
-
} else if (metadata.cost < 1) {
|
|
5069
|
-
formattedCost = metadata.cost.toFixed(3);
|
|
5070
|
-
} else {
|
|
5071
|
-
formattedCost = metadata.cost.toFixed(2);
|
|
5072
|
-
}
|
|
5073
|
-
parts.push(import_chalk.default.dim(`cost: `) + import_chalk.default.cyan(`$${formattedCost}`));
|
|
5074
|
-
}
|
|
5075
|
-
if (parts.length === 0) {
|
|
5076
|
-
return null;
|
|
5077
|
-
}
|
|
5078
|
-
return parts.join(import_chalk.default.dim(" \u2502 "));
|
|
5079
|
-
}
|
|
5080
5101
|
async function executeAction(action, env) {
|
|
5081
5102
|
try {
|
|
5082
5103
|
await action();
|
|
5083
5104
|
} catch (error) {
|
|
5084
5105
|
const message = error instanceof Error ? error.message : String(error);
|
|
5085
|
-
env.stderr.write(`${
|
|
5106
|
+
env.stderr.write(`${import_chalk2.default.red.bold("Error:")} ${message}
|
|
5086
5107
|
`);
|
|
5087
5108
|
env.setExitCode(1);
|
|
5088
5109
|
}
|
|
@@ -5125,26 +5146,15 @@ ${statsPrompt}` : statsPrompt;
|
|
|
5125
5146
|
}
|
|
5126
5147
|
};
|
|
5127
5148
|
}
|
|
5128
|
-
function formatGadgetSummary(result) {
|
|
5129
|
-
const gadgetLabel = import_chalk2.default.magenta.bold(result.gadgetName);
|
|
5130
|
-
const timeLabel = import_chalk2.default.dim(`${Math.round(result.executionTimeMs)}ms`);
|
|
5131
|
-
if (result.error) {
|
|
5132
|
-
return `${import_chalk2.default.red("\u2717")} ${gadgetLabel} ${import_chalk2.default.red("error:")} ${result.error} ${timeLabel}`;
|
|
5133
|
-
}
|
|
5134
|
-
if (result.breaksLoop) {
|
|
5135
|
-
return `${import_chalk2.default.yellow("\u23F9")} ${gadgetLabel} ${import_chalk2.default.yellow("finished:")} ${result.result} ${timeLabel}`;
|
|
5136
|
-
}
|
|
5137
|
-
const maxLen = 80;
|
|
5138
|
-
const shouldTruncate = result.gadgetName !== "TellUser";
|
|
5139
|
-
const resultText = result.result ? shouldTruncate && result.result.length > maxLen ? `${result.result.slice(0, maxLen)}...` : result.result : "";
|
|
5140
|
-
return `${import_chalk2.default.green("\u2713")} ${gadgetLabel} ${import_chalk2.default.dim("\u2192")} ${resultText} ${timeLabel}`;
|
|
5141
|
-
}
|
|
5142
5149
|
async function handleAgentCommand(promptArg, options, env) {
|
|
5143
5150
|
const prompt = await resolvePrompt(promptArg, env);
|
|
5144
5151
|
const client = env.createClient();
|
|
5145
5152
|
const registry = new GadgetRegistry();
|
|
5146
5153
|
if (options.builtins !== false) {
|
|
5147
5154
|
for (const gadget of builtinGadgets) {
|
|
5155
|
+
if (options.builtinInteraction === false && gadget.name === "AskUser") {
|
|
5156
|
+
continue;
|
|
5157
|
+
}
|
|
5148
5158
|
registry.registerByClass(gadget);
|
|
5149
5159
|
}
|
|
5150
5160
|
}
|
|
@@ -5161,16 +5171,28 @@ async function handleAgentCommand(promptArg, options, env) {
|
|
|
5161
5171
|
let finishReason;
|
|
5162
5172
|
let usage;
|
|
5163
5173
|
let iterations = 0;
|
|
5164
|
-
const
|
|
5165
|
-
|
|
5166
|
-
|
|
5174
|
+
const countMessagesTokens = async (model, messages) => {
|
|
5175
|
+
try {
|
|
5176
|
+
return await client.countTokens(model, messages);
|
|
5177
|
+
} catch {
|
|
5178
|
+
const totalChars = messages.reduce((sum, m) => sum + (m.content?.length ?? 0), 0);
|
|
5179
|
+
return Math.round(totalChars / FALLBACK_CHARS_PER_TOKEN);
|
|
5180
|
+
}
|
|
5167
5181
|
};
|
|
5168
5182
|
const builder = new AgentBuilder(client).withModel(options.model).withLogger(env.createLogger("llmist:cli:agent")).withHooks({
|
|
5169
5183
|
observers: {
|
|
5184
|
+
// onLLMCallStart: Start progress indicator for each LLM call
|
|
5185
|
+
// This showcases how to react to agent lifecycle events
|
|
5170
5186
|
onLLMCallStart: async (context) => {
|
|
5171
|
-
const
|
|
5172
|
-
|
|
5187
|
+
const inputTokens = await countMessagesTokens(
|
|
5188
|
+
context.options.model,
|
|
5189
|
+
context.options.messages
|
|
5190
|
+
);
|
|
5191
|
+
progress.startCall(context.options.model, inputTokens);
|
|
5192
|
+
progress.setInputTokens(inputTokens, false);
|
|
5173
5193
|
},
|
|
5194
|
+
// onStreamChunk: Real-time updates as LLM generates tokens
|
|
5195
|
+
// This enables responsive UIs that show progress during generation
|
|
5174
5196
|
onStreamChunk: async (context) => {
|
|
5175
5197
|
progress.update(context.accumulatedText.length);
|
|
5176
5198
|
if (context.usage) {
|
|
@@ -5182,10 +5204,20 @@ async function handleAgentCommand(promptArg, options, env) {
|
|
|
5182
5204
|
}
|
|
5183
5205
|
}
|
|
5184
5206
|
},
|
|
5207
|
+
// onLLMCallComplete: Finalize metrics after each LLM call
|
|
5208
|
+
// This is where you'd typically log metrics or update dashboards
|
|
5185
5209
|
onLLMCallComplete: async (context) => {
|
|
5186
5210
|
finishReason = context.finishReason;
|
|
5187
5211
|
usage = context.usage;
|
|
5188
5212
|
iterations = Math.max(iterations, context.iteration + 1);
|
|
5213
|
+
if (context.usage) {
|
|
5214
|
+
if (context.usage.inputTokens) {
|
|
5215
|
+
progress.setInputTokens(context.usage.inputTokens, false);
|
|
5216
|
+
}
|
|
5217
|
+
if (context.usage.outputTokens) {
|
|
5218
|
+
progress.setOutputTokens(context.usage.outputTokens, false);
|
|
5219
|
+
}
|
|
5220
|
+
}
|
|
5189
5221
|
progress.endCall(context.usage);
|
|
5190
5222
|
}
|
|
5191
5223
|
}
|
|
@@ -5227,7 +5259,8 @@ async function handleAgentCommand(promptArg, options, env) {
|
|
|
5227
5259
|
finishReason,
|
|
5228
5260
|
usage,
|
|
5229
5261
|
iterations,
|
|
5230
|
-
cost: progress.getTotalCost()
|
|
5262
|
+
cost: progress.getTotalCost(),
|
|
5263
|
+
elapsedSeconds: progress.getTotalElapsedSeconds()
|
|
5231
5264
|
});
|
|
5232
5265
|
if (summary) {
|
|
5233
5266
|
env.stderr.write(`${summary}
|
|
@@ -5254,7 +5287,7 @@ function registerAgentCommand(program, env) {
|
|
|
5254
5287
|
OPTION_DESCRIPTIONS.parameterFormat,
|
|
5255
5288
|
parseParameterFormat,
|
|
5256
5289
|
DEFAULT_PARAMETER_FORMAT
|
|
5257
|
-
).option(OPTION_FLAGS.noBuiltins, OPTION_DESCRIPTIONS.noBuiltins).action(
|
|
5290
|
+
).option(OPTION_FLAGS.noBuiltins, OPTION_DESCRIPTIONS.noBuiltins).option(OPTION_FLAGS.noBuiltinInteraction, OPTION_DESCRIPTIONS.noBuiltinInteraction).action(
|
|
5258
5291
|
(prompt, options) => executeAction(() => handleAgentCommand(prompt, options, env), env)
|
|
5259
5292
|
);
|
|
5260
5293
|
}
|
|
@@ -5392,7 +5425,7 @@ function renderCompactTable(models, stream2) {
|
|
|
5392
5425
|
);
|
|
5393
5426
|
stream2.write(import_chalk3.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
5394
5427
|
for (const model of models) {
|
|
5395
|
-
const contextFormatted =
|
|
5428
|
+
const contextFormatted = formatTokens2(model.contextWindow);
|
|
5396
5429
|
const inputPrice = `$${model.pricing.input.toFixed(2)}`;
|
|
5397
5430
|
const outputPrice = `$${model.pricing.output.toFixed(2)}`;
|
|
5398
5431
|
stream2.write(
|
|
@@ -5411,9 +5444,9 @@ function renderVerboseTable(models, stream2) {
|
|
|
5411
5444
|
stream2.write(import_chalk3.default.dim(" " + "\u2500".repeat(60)) + "\n");
|
|
5412
5445
|
stream2.write(` ${import_chalk3.default.dim("Name:")} ${import_chalk3.default.white(model.displayName)}
|
|
5413
5446
|
`);
|
|
5414
|
-
stream2.write(` ${import_chalk3.default.dim("Context:")} ${import_chalk3.default.yellow(
|
|
5447
|
+
stream2.write(` ${import_chalk3.default.dim("Context:")} ${import_chalk3.default.yellow(formatTokens2(model.contextWindow))}
|
|
5415
5448
|
`);
|
|
5416
|
-
stream2.write(` ${import_chalk3.default.dim("Max Output:")} ${import_chalk3.default.yellow(
|
|
5449
|
+
stream2.write(` ${import_chalk3.default.dim("Max Output:")} ${import_chalk3.default.yellow(formatTokens2(model.maxOutputTokens))}
|
|
5417
5450
|
`);
|
|
5418
5451
|
stream2.write(` ${import_chalk3.default.dim("Pricing:")} ${import_chalk3.default.cyan(`$${model.pricing.input.toFixed(2)} input`)} ${import_chalk3.default.dim("/")} ${import_chalk3.default.cyan(`$${model.pricing.output.toFixed(2)} output`)} ${import_chalk3.default.dim("(per 1M tokens)")}
|
|
5419
5452
|
`);
|
|
@@ -5476,7 +5509,7 @@ function renderJSON(models, stream2) {
|
|
|
5476
5509
|
};
|
|
5477
5510
|
stream2.write(JSON.stringify(output, null, 2) + "\n");
|
|
5478
5511
|
}
|
|
5479
|
-
function
|
|
5512
|
+
function formatTokens2(count) {
|
|
5480
5513
|
if (count >= 1e6) {
|
|
5481
5514
|
return `${(count / 1e6).toFixed(1)}M tokens`;
|
|
5482
5515
|
} else if (count >= 1e3) {
|