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