llmist 0.1.4 → 0.1.5
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/README.md +65 -11
- package/dist/cli.cjs +127 -56
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +127 -56
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +335 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +374 -48
- package/dist/index.d.ts +374 -48
- package/dist/index.js +335 -40
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -63,7 +63,7 @@ import { Command, InvalidArgumentError as InvalidArgumentError3 } from "commande
|
|
|
63
63
|
// package.json
|
|
64
64
|
var package_default = {
|
|
65
65
|
name: "llmist",
|
|
66
|
-
version: "0.1.
|
|
66
|
+
version: "0.1.5",
|
|
67
67
|
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.",
|
|
68
68
|
type: "module",
|
|
69
69
|
main: "dist/index.cjs",
|
|
@@ -169,11 +169,10 @@ init_builder();
|
|
|
169
169
|
init_registry();
|
|
170
170
|
init_constants();
|
|
171
171
|
import { createInterface } from "node:readline/promises";
|
|
172
|
-
import
|
|
172
|
+
import chalk2 from "chalk";
|
|
173
173
|
import { InvalidArgumentError as InvalidArgumentError2 } from "commander";
|
|
174
174
|
|
|
175
175
|
// src/cli/builtin-gadgets.ts
|
|
176
|
-
import chalk from "chalk";
|
|
177
176
|
import { z } from "zod";
|
|
178
177
|
init_exceptions();
|
|
179
178
|
var askUser = createGadget({
|
|
@@ -195,17 +194,17 @@ var tellUser = createGadget({
|
|
|
195
194
|
type: z.enum(["info", "success", "warning", "error"]).default("info").describe("Message type: info, success, warning, or error")
|
|
196
195
|
}),
|
|
197
196
|
execute: ({ message, done, type }) => {
|
|
198
|
-
const
|
|
199
|
-
info:
|
|
200
|
-
success:
|
|
201
|
-
warning:
|
|
202
|
-
error:
|
|
197
|
+
const prefixes = {
|
|
198
|
+
info: "\u2139\uFE0F ",
|
|
199
|
+
success: "\u2705 ",
|
|
200
|
+
warning: "\u26A0\uFE0F ",
|
|
201
|
+
error: "\u274C "
|
|
203
202
|
};
|
|
204
|
-
const
|
|
203
|
+
const plainResult = prefixes[type] + message;
|
|
205
204
|
if (done) {
|
|
206
|
-
throw new BreakLoopException(
|
|
205
|
+
throw new BreakLoopException(plainResult);
|
|
207
206
|
}
|
|
208
|
-
return
|
|
207
|
+
return plainResult;
|
|
209
208
|
}
|
|
210
209
|
});
|
|
211
210
|
var builtinGadgets = [askUser, tellUser];
|
|
@@ -308,7 +307,7 @@ async function loadGadgets(specifiers, cwd, importer = (specifier) => import(spe
|
|
|
308
307
|
|
|
309
308
|
// src/cli/utils.ts
|
|
310
309
|
init_constants();
|
|
311
|
-
import
|
|
310
|
+
import chalk from "chalk";
|
|
312
311
|
import { InvalidArgumentError } from "commander";
|
|
313
312
|
function createNumericParser({
|
|
314
313
|
label,
|
|
@@ -366,9 +365,10 @@ function isInteractive(stream) {
|
|
|
366
365
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
367
366
|
var SPINNER_DELAY_MS = 500;
|
|
368
367
|
var StreamProgress = class {
|
|
369
|
-
constructor(target, isTTY) {
|
|
368
|
+
constructor(target, isTTY, modelRegistry) {
|
|
370
369
|
this.target = target;
|
|
371
370
|
this.isTTY = isTTY;
|
|
371
|
+
this.modelRegistry = modelRegistry;
|
|
372
372
|
}
|
|
373
373
|
// Animation state
|
|
374
374
|
frameIndex = 0;
|
|
@@ -389,6 +389,7 @@ var StreamProgress = class {
|
|
|
389
389
|
// Cumulative stats (cumulative mode)
|
|
390
390
|
totalStartTime = Date.now();
|
|
391
391
|
totalTokens = 0;
|
|
392
|
+
totalCost = 0;
|
|
392
393
|
iterations = 0;
|
|
393
394
|
/**
|
|
394
395
|
* Starts a new LLM call. Switches to streaming mode.
|
|
@@ -415,6 +416,20 @@ var StreamProgress = class {
|
|
|
415
416
|
this.iterations++;
|
|
416
417
|
if (usage) {
|
|
417
418
|
this.totalTokens += usage.totalTokens;
|
|
419
|
+
if (this.modelRegistry && this.model) {
|
|
420
|
+
try {
|
|
421
|
+
const modelName = this.model.includes(":") ? this.model.split(":")[1] : this.model;
|
|
422
|
+
const cost = this.modelRegistry.estimateCost(
|
|
423
|
+
modelName,
|
|
424
|
+
usage.inputTokens,
|
|
425
|
+
usage.outputTokens
|
|
426
|
+
);
|
|
427
|
+
if (cost) {
|
|
428
|
+
this.totalCost += cost.totalCost;
|
|
429
|
+
}
|
|
430
|
+
} catch {
|
|
431
|
+
}
|
|
432
|
+
}
|
|
418
433
|
}
|
|
419
434
|
this.pause();
|
|
420
435
|
this.mode = "cumulative";
|
|
@@ -478,33 +493,39 @@ var StreamProgress = class {
|
|
|
478
493
|
const outTokens = this.callOutputTokensEstimated ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN) : this.callOutputTokens;
|
|
479
494
|
const parts = [];
|
|
480
495
|
if (this.model) {
|
|
481
|
-
parts.push(
|
|
496
|
+
parts.push(chalk.cyan(this.model));
|
|
482
497
|
}
|
|
483
498
|
if (this.callInputTokens > 0) {
|
|
484
499
|
const prefix = this.callInputTokensEstimated ? "~" : "";
|
|
485
|
-
parts.push(
|
|
500
|
+
parts.push(chalk.dim("out:") + chalk.yellow(` ${prefix}${this.callInputTokens}`));
|
|
486
501
|
}
|
|
487
502
|
if (this.isStreaming || outTokens > 0) {
|
|
488
503
|
const prefix = this.callOutputTokensEstimated ? "~" : "";
|
|
489
|
-
parts.push(
|
|
504
|
+
parts.push(chalk.dim("in:") + chalk.green(` ${prefix}${outTokens}`));
|
|
505
|
+
}
|
|
506
|
+
if (this.totalCost > 0) {
|
|
507
|
+
parts.push(chalk.dim("cost:") + chalk.cyan(` $${this.formatCost(this.totalCost)}`));
|
|
490
508
|
}
|
|
491
|
-
parts.push(
|
|
492
|
-
this.target.write(`\r${
|
|
509
|
+
parts.push(chalk.dim(`${elapsed}s`));
|
|
510
|
+
this.target.write(`\r${chalk.cyan(spinner)} ${parts.join(chalk.dim(" | "))}`);
|
|
493
511
|
}
|
|
494
512
|
renderCumulativeMode(spinner) {
|
|
495
513
|
const elapsed = ((Date.now() - this.totalStartTime) / 1e3).toFixed(1);
|
|
496
514
|
const parts = [];
|
|
497
515
|
if (this.model) {
|
|
498
|
-
parts.push(
|
|
516
|
+
parts.push(chalk.cyan(this.model));
|
|
499
517
|
}
|
|
500
518
|
if (this.totalTokens > 0) {
|
|
501
|
-
parts.push(
|
|
519
|
+
parts.push(chalk.dim("total:") + chalk.magenta(` ${this.totalTokens}`));
|
|
502
520
|
}
|
|
503
521
|
if (this.iterations > 0) {
|
|
504
|
-
parts.push(
|
|
522
|
+
parts.push(chalk.dim("iter:") + chalk.blue(` ${this.iterations}`));
|
|
505
523
|
}
|
|
506
|
-
|
|
507
|
-
|
|
524
|
+
if (this.totalCost > 0) {
|
|
525
|
+
parts.push(chalk.dim("cost:") + chalk.cyan(` $${this.formatCost(this.totalCost)}`));
|
|
526
|
+
}
|
|
527
|
+
parts.push(chalk.dim(`${elapsed}s`));
|
|
528
|
+
this.target.write(`\r${chalk.cyan(spinner)} ${parts.join(chalk.dim(" | "))}`);
|
|
508
529
|
}
|
|
509
530
|
/**
|
|
510
531
|
* Pauses the progress indicator and clears the line.
|
|
@@ -532,6 +553,12 @@ var StreamProgress = class {
|
|
|
532
553
|
complete() {
|
|
533
554
|
this.pause();
|
|
534
555
|
}
|
|
556
|
+
/**
|
|
557
|
+
* Returns the total accumulated cost across all calls.
|
|
558
|
+
*/
|
|
559
|
+
getTotalCost() {
|
|
560
|
+
return this.totalCost;
|
|
561
|
+
}
|
|
535
562
|
/**
|
|
536
563
|
* Returns a formatted prompt string with stats (like bash PS1).
|
|
537
564
|
* Shows current call stats during streaming, cumulative stats otherwise.
|
|
@@ -546,25 +573,28 @@ var StreamProgress = class {
|
|
|
546
573
|
if (this.callInputTokens > 0) {
|
|
547
574
|
const prefix = this.callInputTokensEstimated ? "~" : "";
|
|
548
575
|
parts.push(
|
|
549
|
-
|
|
576
|
+
chalk.dim("out:") + chalk.yellow(` ${prefix}${this.formatTokens(this.callInputTokens)}`)
|
|
550
577
|
);
|
|
551
578
|
}
|
|
552
579
|
if (outTokens > 0) {
|
|
553
580
|
const prefix = outEstimated ? "~" : "";
|
|
554
|
-
parts.push(
|
|
581
|
+
parts.push(chalk.dim("in:") + chalk.green(` ${prefix}${this.formatTokens(outTokens)}`));
|
|
555
582
|
}
|
|
556
|
-
parts.push(
|
|
583
|
+
parts.push(chalk.dim(`${elapsed}s`));
|
|
557
584
|
} else {
|
|
558
585
|
const elapsed = Math.round((Date.now() - this.totalStartTime) / 1e3);
|
|
559
586
|
if (this.totalTokens > 0) {
|
|
560
|
-
parts.push(
|
|
587
|
+
parts.push(chalk.magenta(this.formatTokens(this.totalTokens)));
|
|
561
588
|
}
|
|
562
589
|
if (this.iterations > 0) {
|
|
563
|
-
parts.push(
|
|
590
|
+
parts.push(chalk.blue(`i${this.iterations}`));
|
|
591
|
+
}
|
|
592
|
+
if (this.totalCost > 0) {
|
|
593
|
+
parts.push(chalk.cyan(`$${this.formatCost(this.totalCost)}`));
|
|
564
594
|
}
|
|
565
|
-
parts.push(
|
|
595
|
+
parts.push(chalk.dim(`${elapsed}s`));
|
|
566
596
|
}
|
|
567
|
-
return `${parts.join(
|
|
597
|
+
return `${parts.join(chalk.dim(" \u2502 "))} ${chalk.green(">")} `;
|
|
568
598
|
}
|
|
569
599
|
/**
|
|
570
600
|
* Formats token count compactly (3625 -> "3.6k").
|
|
@@ -572,6 +602,21 @@ var StreamProgress = class {
|
|
|
572
602
|
formatTokens(tokens) {
|
|
573
603
|
return tokens >= 1e3 ? `${(tokens / 1e3).toFixed(1)}k` : `${tokens}`;
|
|
574
604
|
}
|
|
605
|
+
/**
|
|
606
|
+
* Formats cost compactly (0.0001234 -> "0.00012", 0.1234 -> "0.12", 1.234 -> "1.23").
|
|
607
|
+
*/
|
|
608
|
+
formatCost(cost) {
|
|
609
|
+
if (cost < 1e-3) {
|
|
610
|
+
return cost.toFixed(5);
|
|
611
|
+
}
|
|
612
|
+
if (cost < 0.01) {
|
|
613
|
+
return cost.toFixed(4);
|
|
614
|
+
}
|
|
615
|
+
if (cost < 1) {
|
|
616
|
+
return cost.toFixed(3);
|
|
617
|
+
}
|
|
618
|
+
return cost.toFixed(2);
|
|
619
|
+
}
|
|
575
620
|
};
|
|
576
621
|
async function readStream(stream) {
|
|
577
622
|
const chunks = [];
|
|
@@ -603,29 +648,42 @@ async function resolvePrompt(promptArg, env) {
|
|
|
603
648
|
function renderSummary(metadata) {
|
|
604
649
|
const parts = [];
|
|
605
650
|
if (metadata.iterations !== void 0) {
|
|
606
|
-
parts.push(
|
|
651
|
+
parts.push(chalk.dim(`iterations: ${metadata.iterations}`));
|
|
607
652
|
}
|
|
608
653
|
if (metadata.finishReason) {
|
|
609
|
-
parts.push(
|
|
654
|
+
parts.push(chalk.dim(`finish: ${metadata.finishReason}`));
|
|
610
655
|
}
|
|
611
656
|
if (metadata.usage) {
|
|
612
657
|
const { inputTokens, outputTokens, totalTokens } = metadata.usage;
|
|
613
658
|
parts.push(
|
|
614
|
-
|
|
659
|
+
chalk.dim(`tokens: `) + chalk.cyan(`${totalTokens}`) + chalk.dim(` (in: ${inputTokens}, out: ${outputTokens})`)
|
|
615
660
|
);
|
|
616
661
|
}
|
|
662
|
+
if (metadata.cost !== void 0 && metadata.cost > 0) {
|
|
663
|
+
let formattedCost;
|
|
664
|
+
if (metadata.cost < 1e-3) {
|
|
665
|
+
formattedCost = metadata.cost.toFixed(5);
|
|
666
|
+
} else if (metadata.cost < 0.01) {
|
|
667
|
+
formattedCost = metadata.cost.toFixed(4);
|
|
668
|
+
} else if (metadata.cost < 1) {
|
|
669
|
+
formattedCost = metadata.cost.toFixed(3);
|
|
670
|
+
} else {
|
|
671
|
+
formattedCost = metadata.cost.toFixed(2);
|
|
672
|
+
}
|
|
673
|
+
parts.push(chalk.dim(`cost: `) + chalk.cyan(`$${formattedCost}`));
|
|
674
|
+
}
|
|
617
675
|
if (parts.length === 0) {
|
|
618
676
|
return null;
|
|
619
677
|
}
|
|
620
|
-
return `${
|
|
621
|
-
${parts.join(
|
|
678
|
+
return `${chalk.dim("\u2500".repeat(40))}
|
|
679
|
+
${parts.join(chalk.dim(" \u2502 "))}`;
|
|
622
680
|
}
|
|
623
681
|
async function executeAction(action, env) {
|
|
624
682
|
try {
|
|
625
683
|
await action();
|
|
626
684
|
} catch (error) {
|
|
627
685
|
const message = error instanceof Error ? error.message : String(error);
|
|
628
|
-
env.stderr.write(`${
|
|
686
|
+
env.stderr.write(`${chalk.red.bold("Error:")} ${message}
|
|
629
687
|
`);
|
|
630
688
|
env.setExitCode(1);
|
|
631
689
|
}
|
|
@@ -669,17 +727,18 @@ ${statsPrompt}` : statsPrompt;
|
|
|
669
727
|
};
|
|
670
728
|
}
|
|
671
729
|
function formatGadgetSummary(result) {
|
|
672
|
-
const gadgetLabel =
|
|
673
|
-
const timeLabel =
|
|
730
|
+
const gadgetLabel = chalk2.magenta.bold(result.gadgetName);
|
|
731
|
+
const timeLabel = chalk2.dim(`${Math.round(result.executionTimeMs)}ms`);
|
|
674
732
|
if (result.error) {
|
|
675
|
-
return `${
|
|
733
|
+
return `${chalk2.red("\u2717")} ${gadgetLabel} ${chalk2.red("error:")} ${result.error} ${timeLabel}`;
|
|
676
734
|
}
|
|
677
735
|
if (result.breaksLoop) {
|
|
678
|
-
return `${
|
|
736
|
+
return `${chalk2.yellow("\u23F9")} ${gadgetLabel} ${chalk2.yellow("finished:")} ${result.result} ${timeLabel}`;
|
|
679
737
|
}
|
|
680
738
|
const maxLen = 80;
|
|
681
|
-
const
|
|
682
|
-
|
|
739
|
+
const shouldTruncate = result.gadgetName !== "TellUser";
|
|
740
|
+
const resultText = result.result ? shouldTruncate && result.result.length > maxLen ? `${result.result.slice(0, maxLen)}...` : result.result : "";
|
|
741
|
+
return `${chalk2.green("\u2713")} ${gadgetLabel} ${chalk2.dim("\u2192")} ${resultText} ${timeLabel}`;
|
|
683
742
|
}
|
|
684
743
|
async function handleAgentCommand(promptArg, options, env) {
|
|
685
744
|
const prompt = await resolvePrompt(promptArg, env);
|
|
@@ -699,7 +758,7 @@ async function handleAgentCommand(promptArg, options, env) {
|
|
|
699
758
|
}
|
|
700
759
|
const printer = new StreamPrinter(env.stdout);
|
|
701
760
|
const stderrTTY = env.stderr.isTTY === true;
|
|
702
|
-
const progress = new StreamProgress(env.stderr, stderrTTY);
|
|
761
|
+
const progress = new StreamProgress(env.stderr, stderrTTY, client.modelRegistry);
|
|
703
762
|
let finishReason;
|
|
704
763
|
let usage;
|
|
705
764
|
let iterations = 0;
|
|
@@ -756,16 +815,25 @@ async function handleAgentCommand(promptArg, options, env) {
|
|
|
756
815
|
printer.write(event.content);
|
|
757
816
|
} else if (event.type === "gadget_result") {
|
|
758
817
|
progress.pause();
|
|
759
|
-
|
|
818
|
+
if (stderrTTY) {
|
|
819
|
+
env.stderr.write(`${formatGadgetSummary(event.result)}
|
|
760
820
|
`);
|
|
821
|
+
}
|
|
761
822
|
}
|
|
762
823
|
}
|
|
763
824
|
progress.complete();
|
|
764
825
|
printer.ensureNewline();
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
826
|
+
if (stderrTTY) {
|
|
827
|
+
const summary = renderSummary({
|
|
828
|
+
finishReason,
|
|
829
|
+
usage,
|
|
830
|
+
iterations,
|
|
831
|
+
cost: progress.getTotalCost()
|
|
832
|
+
});
|
|
833
|
+
if (summary) {
|
|
834
|
+
env.stderr.write(`${summary}
|
|
768
835
|
`);
|
|
836
|
+
}
|
|
769
837
|
}
|
|
770
838
|
}
|
|
771
839
|
function registerAgentCommand(program, env) {
|
|
@@ -811,7 +879,7 @@ async function handleCompleteCommand(promptArg, options, env) {
|
|
|
811
879
|
});
|
|
812
880
|
const printer = new StreamPrinter(env.stdout);
|
|
813
881
|
const stderrTTY = env.stderr.isTTY === true;
|
|
814
|
-
const progress = new StreamProgress(env.stderr, stderrTTY);
|
|
882
|
+
const progress = new StreamProgress(env.stderr, stderrTTY, client.modelRegistry);
|
|
815
883
|
const estimatedInputTokens = Math.round(prompt.length / FALLBACK_CHARS_PER_TOKEN);
|
|
816
884
|
progress.startCall(options.model, estimatedInputTokens);
|
|
817
885
|
let finishReason;
|
|
@@ -837,12 +905,15 @@ async function handleCompleteCommand(promptArg, options, env) {
|
|
|
837
905
|
finishReason = chunk.finishReason;
|
|
838
906
|
}
|
|
839
907
|
}
|
|
908
|
+
progress.endCall(usage);
|
|
840
909
|
progress.complete();
|
|
841
910
|
printer.ensureNewline();
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
911
|
+
if (stderrTTY) {
|
|
912
|
+
const summary = renderSummary({ finishReason, usage, cost: progress.getTotalCost() });
|
|
913
|
+
if (summary) {
|
|
914
|
+
env.stderr.write(`${summary}
|
|
845
915
|
`);
|
|
916
|
+
}
|
|
846
917
|
}
|
|
847
918
|
}
|
|
848
919
|
function registerCompleteCommand(program, env) {
|
|
@@ -866,7 +937,7 @@ function registerCompleteCommand(program, env) {
|
|
|
866
937
|
init_client();
|
|
867
938
|
init_logger();
|
|
868
939
|
import readline from "node:readline";
|
|
869
|
-
import
|
|
940
|
+
import chalk3 from "chalk";
|
|
870
941
|
var LOG_LEVEL_MAP = {
|
|
871
942
|
silly: 0,
|
|
872
943
|
trace: 1,
|
|
@@ -910,14 +981,14 @@ function createPromptFunction(stdin, stdout) {
|
|
|
910
981
|
output: stdout
|
|
911
982
|
});
|
|
912
983
|
stdout.write("\n");
|
|
913
|
-
stdout.write(`${
|
|
984
|
+
stdout.write(`${chalk3.cyan("\u2500".repeat(60))}
|
|
914
985
|
`);
|
|
915
|
-
stdout.write(
|
|
986
|
+
stdout.write(chalk3.cyan.bold("\u{1F916} Agent asks:\n"));
|
|
916
987
|
stdout.write(`${question}
|
|
917
988
|
`);
|
|
918
|
-
stdout.write(`${
|
|
989
|
+
stdout.write(`${chalk3.cyan("\u2500".repeat(60))}
|
|
919
990
|
`);
|
|
920
|
-
rl.question(
|
|
991
|
+
rl.question(chalk3.green.bold("You: "), (answer) => {
|
|
921
992
|
rl.close();
|
|
922
993
|
resolve(answer);
|
|
923
994
|
});
|