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 CHANGED
@@ -1,8 +1,8 @@
1
1
  # llmist
2
2
 
3
3
  [![CI](https://github.com/zbigniewsobiecki/llmist/actions/workflows/ci.yml/badge.svg)](https://github.com/zbigniewsobiecki/llmist/actions/workflows/ci.yml)
4
- [![codecov](https://codecov.io/gh/zbigniewsobiecki/llmist/branch/main/graph/badge.svg)](https://codecov.io/gh/zbigniewsobiecki/llmist)
5
- [![npm version](https://badge.fury.io/js/llmist.svg)](https://www.npmjs.com/package/llmist)
4
+ [![codecov](https://codecov.io/gh/zbigniewsobiecki/llmist/graph/badge.svg)](https://codecov.io/gh/zbigniewsobiecki/llmist)
5
+ [![npm version](https://img.shields.io/npm/v/llmist.svg)](https://www.npmjs.com/package/llmist)
6
6
  [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
8
  > **Universal TypeScript LLM client with streaming-first tool execution and simple, extensible agent framework**
@@ -153,31 +153,85 @@ const calculator = createGadget({
153
153
 
154
154
  ### 🪝 Lifecycle Hooks
155
155
 
156
+ Monitor, transform, and control agent execution with ready-to-use presets or custom hooks:
157
+
158
+ **Quick start with presets:**
159
+
156
160
  ```typescript
157
- import { HookPresets } from 'llmist';
161
+ import { LLMist, HookPresets } from 'llmist';
162
+
163
+ // Full monitoring suite (recommended for development)
164
+ await LLMist.createAgent()
165
+ .withHooks(HookPresets.monitoring())
166
+ .ask('Your prompt');
167
+ // Output: Logs + timing + token tracking + error logging
158
168
 
159
- // Use presets for instant monitoring
169
+ // Combine specific presets for focused monitoring
160
170
  await LLMist.createAgent()
161
- .withHooks(HookPresets.monitoring()) // Logs + timing + tokens + errors
171
+ .withHooks(HookPresets.merge(
172
+ HookPresets.timing(),
173
+ HookPresets.tokenTracking()
174
+ ))
162
175
  .ask('Your prompt');
176
+ ```
163
177
 
164
- // Or combine specific presets
165
- .withHooks(HookPresets.merge(
166
- HookPresets.timing(),
167
- HookPresets.tokenTracking()
168
- ))
178
+ **Available presets:**
179
+ - `logging()` / `logging({ verbose: true })` - Event logging with optional details
180
+ - `timing()` - Execution time measurements
181
+ - `tokenTracking()` - Cumulative token usage and cost tracking
182
+ - `errorLogging()` - Detailed error information
183
+ - `silent()` - No output (for testing)
184
+ - `monitoring()` - All-in-one preset combining logging, timing, tokens, and errors
185
+ - `merge()` - Combine multiple presets or add custom hooks
169
186
 
170
- // Or write custom hooks
187
+ **Production vs Development patterns:**
188
+
189
+ ```typescript
190
+ // Environment-based configuration
191
+ const isDev = process.env.NODE_ENV === 'development';
192
+ const hooks = isDev
193
+ ? HookPresets.monitoring({ verbose: true }) // Full visibility in dev
194
+ : HookPresets.merge(
195
+ HookPresets.errorLogging(), // Only errors in prod
196
+ HookPresets.tokenTracking() // Track costs
197
+ );
198
+
199
+ await LLMist.createAgent()
200
+ .withHooks(hooks)
201
+ .ask('Your prompt');
202
+ ```
203
+
204
+ **Custom hooks for advanced control:**
205
+
206
+ ```typescript
207
+ // Observers: read-only monitoring
171
208
  .withHooks({
172
209
  observers: {
173
210
  onLLMCallComplete: async (ctx) => {
174
211
  console.log(`Used ${ctx.usage?.totalTokens} tokens`);
212
+ await sendMetricsToDataDog(ctx);
175
213
  },
176
214
  },
215
+ })
216
+
217
+ // Interceptors: transform data in flight
218
+ .withHooks({
177
219
  interceptors: {
178
220
  interceptTextChunk: (chunk) => chunk.toUpperCase(),
179
221
  },
180
222
  })
223
+
224
+ // Controllers: control execution flow
225
+ .withHooks({
226
+ controllers: {
227
+ beforeLLMCall: async (ctx) => {
228
+ if (shouldCache(ctx)) {
229
+ return { action: 'skip', syntheticResponse: cachedResponse };
230
+ }
231
+ return { action: 'proceed' };
232
+ },
233
+ },
234
+ })
181
235
  ```
182
236
 
183
237
  📖 **[Hooks Guide](./docs/HOOKS.md)** | **[Examples](./examples/03-hooks.ts)**
package/dist/cli.cjs CHANGED
@@ -4253,7 +4253,7 @@ var import_commander3 = require("commander");
4253
4253
  // package.json
4254
4254
  var package_default = {
4255
4255
  name: "llmist",
4256
- version: "0.1.4",
4256
+ version: "0.1.6",
4257
4257
  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.",
4258
4258
  type: "module",
4259
4259
  main: "dist/index.cjs",
@@ -4356,14 +4356,13 @@ var package_default = {
4356
4356
 
4357
4357
  // src/cli/agent-command.ts
4358
4358
  var import_promises = require("readline/promises");
4359
- var import_chalk3 = __toESM(require("chalk"), 1);
4359
+ var import_chalk2 = __toESM(require("chalk"), 1);
4360
4360
  var import_commander2 = require("commander");
4361
4361
  init_builder();
4362
4362
  init_registry();
4363
4363
  init_constants2();
4364
4364
 
4365
4365
  // src/cli/builtin-gadgets.ts
4366
- var import_chalk = __toESM(require("chalk"), 1);
4367
4366
  var import_zod = require("zod");
4368
4367
 
4369
4368
  // src/gadgets/gadget.ts
@@ -4539,17 +4538,17 @@ var tellUser = createGadget({
4539
4538
  type: import_zod.z.enum(["info", "success", "warning", "error"]).default("info").describe("Message type: info, success, warning, or error")
4540
4539
  }),
4541
4540
  execute: ({ message, done, type }) => {
4542
- const formatters = {
4543
- info: (msg) => import_chalk.default.blue(`\u2139\uFE0F ${msg}`),
4544
- success: (msg) => import_chalk.default.green(`\u2705 ${msg}`),
4545
- warning: (msg) => import_chalk.default.yellow(`\u26A0\uFE0F ${msg}`),
4546
- error: (msg) => import_chalk.default.red(`\u274C ${msg}`)
4541
+ const prefixes = {
4542
+ info: "\u2139\uFE0F ",
4543
+ success: "\u2705 ",
4544
+ warning: "\u26A0\uFE0F ",
4545
+ error: "\u274C "
4547
4546
  };
4548
- const formatted = formatters[type](message);
4547
+ const plainResult = prefixes[type] + message;
4549
4548
  if (done) {
4550
- throw new BreakLoopException(formatted);
4549
+ throw new BreakLoopException(plainResult);
4551
4550
  }
4552
- return formatted;
4551
+ return plainResult;
4553
4552
  }
4554
4553
  });
4555
4554
  var builtinGadgets = [askUser, tellUser];
@@ -4651,7 +4650,7 @@ async function loadGadgets(specifiers, cwd, importer = (specifier) => import(spe
4651
4650
  }
4652
4651
 
4653
4652
  // src/cli/utils.ts
4654
- var import_chalk2 = __toESM(require("chalk"), 1);
4653
+ var import_chalk = __toESM(require("chalk"), 1);
4655
4654
  var import_commander = require("commander");
4656
4655
  init_constants2();
4657
4656
  function createNumericParser({
@@ -4710,9 +4709,10 @@ function isInteractive(stream2) {
4710
4709
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
4711
4710
  var SPINNER_DELAY_MS = 500;
4712
4711
  var StreamProgress = class {
4713
- constructor(target, isTTY) {
4712
+ constructor(target, isTTY, modelRegistry) {
4714
4713
  this.target = target;
4715
4714
  this.isTTY = isTTY;
4715
+ this.modelRegistry = modelRegistry;
4716
4716
  }
4717
4717
  // Animation state
4718
4718
  frameIndex = 0;
@@ -4733,6 +4733,7 @@ var StreamProgress = class {
4733
4733
  // Cumulative stats (cumulative mode)
4734
4734
  totalStartTime = Date.now();
4735
4735
  totalTokens = 0;
4736
+ totalCost = 0;
4736
4737
  iterations = 0;
4737
4738
  /**
4738
4739
  * Starts a new LLM call. Switches to streaming mode.
@@ -4759,6 +4760,20 @@ var StreamProgress = class {
4759
4760
  this.iterations++;
4760
4761
  if (usage) {
4761
4762
  this.totalTokens += usage.totalTokens;
4763
+ if (this.modelRegistry && this.model) {
4764
+ try {
4765
+ const modelName = this.model.includes(":") ? this.model.split(":")[1] : this.model;
4766
+ const cost = this.modelRegistry.estimateCost(
4767
+ modelName,
4768
+ usage.inputTokens,
4769
+ usage.outputTokens
4770
+ );
4771
+ if (cost) {
4772
+ this.totalCost += cost.totalCost;
4773
+ }
4774
+ } catch {
4775
+ }
4776
+ }
4762
4777
  }
4763
4778
  this.pause();
4764
4779
  this.mode = "cumulative";
@@ -4822,33 +4837,39 @@ var StreamProgress = class {
4822
4837
  const outTokens = this.callOutputTokensEstimated ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN) : this.callOutputTokens;
4823
4838
  const parts = [];
4824
4839
  if (this.model) {
4825
- parts.push(import_chalk2.default.cyan(this.model));
4840
+ parts.push(import_chalk.default.cyan(this.model));
4826
4841
  }
4827
4842
  if (this.callInputTokens > 0) {
4828
4843
  const prefix = this.callInputTokensEstimated ? "~" : "";
4829
- parts.push(import_chalk2.default.dim("out:") + import_chalk2.default.yellow(` ${prefix}${this.callInputTokens}`));
4844
+ parts.push(import_chalk.default.dim("out:") + import_chalk.default.yellow(` ${prefix}${this.callInputTokens}`));
4830
4845
  }
4831
4846
  if (this.isStreaming || outTokens > 0) {
4832
4847
  const prefix = this.callOutputTokensEstimated ? "~" : "";
4833
- parts.push(import_chalk2.default.dim("in:") + import_chalk2.default.green(` ${prefix}${outTokens}`));
4848
+ parts.push(import_chalk.default.dim("in:") + import_chalk.default.green(` ${prefix}${outTokens}`));
4849
+ }
4850
+ if (this.totalCost > 0) {
4851
+ parts.push(import_chalk.default.dim("cost:") + import_chalk.default.cyan(` $${this.formatCost(this.totalCost)}`));
4834
4852
  }
4835
- parts.push(import_chalk2.default.dim(`${elapsed}s`));
4836
- this.target.write(`\r${import_chalk2.default.cyan(spinner)} ${parts.join(import_chalk2.default.dim(" | "))}`);
4853
+ parts.push(import_chalk.default.dim(`${elapsed}s`));
4854
+ this.target.write(`\r${import_chalk.default.cyan(spinner)} ${parts.join(import_chalk.default.dim(" | "))}`);
4837
4855
  }
4838
4856
  renderCumulativeMode(spinner) {
4839
4857
  const elapsed = ((Date.now() - this.totalStartTime) / 1e3).toFixed(1);
4840
4858
  const parts = [];
4841
4859
  if (this.model) {
4842
- parts.push(import_chalk2.default.cyan(this.model));
4860
+ parts.push(import_chalk.default.cyan(this.model));
4843
4861
  }
4844
4862
  if (this.totalTokens > 0) {
4845
- parts.push(import_chalk2.default.dim("total:") + import_chalk2.default.magenta(` ${this.totalTokens}`));
4863
+ parts.push(import_chalk.default.dim("total:") + import_chalk.default.magenta(` ${this.totalTokens}`));
4846
4864
  }
4847
4865
  if (this.iterations > 0) {
4848
- parts.push(import_chalk2.default.dim("iter:") + import_chalk2.default.blue(` ${this.iterations}`));
4866
+ parts.push(import_chalk.default.dim("iter:") + import_chalk.default.blue(` ${this.iterations}`));
4849
4867
  }
4850
- parts.push(import_chalk2.default.dim(`${elapsed}s`));
4851
- this.target.write(`\r${import_chalk2.default.cyan(spinner)} ${parts.join(import_chalk2.default.dim(" | "))}`);
4868
+ if (this.totalCost > 0) {
4869
+ parts.push(import_chalk.default.dim("cost:") + import_chalk.default.cyan(` $${this.formatCost(this.totalCost)}`));
4870
+ }
4871
+ parts.push(import_chalk.default.dim(`${elapsed}s`));
4872
+ this.target.write(`\r${import_chalk.default.cyan(spinner)} ${parts.join(import_chalk.default.dim(" | "))}`);
4852
4873
  }
4853
4874
  /**
4854
4875
  * Pauses the progress indicator and clears the line.
@@ -4876,6 +4897,12 @@ var StreamProgress = class {
4876
4897
  complete() {
4877
4898
  this.pause();
4878
4899
  }
4900
+ /**
4901
+ * Returns the total accumulated cost across all calls.
4902
+ */
4903
+ getTotalCost() {
4904
+ return this.totalCost;
4905
+ }
4879
4906
  /**
4880
4907
  * Returns a formatted prompt string with stats (like bash PS1).
4881
4908
  * Shows current call stats during streaming, cumulative stats otherwise.
@@ -4890,25 +4917,28 @@ var StreamProgress = class {
4890
4917
  if (this.callInputTokens > 0) {
4891
4918
  const prefix = this.callInputTokensEstimated ? "~" : "";
4892
4919
  parts.push(
4893
- import_chalk2.default.dim("out:") + import_chalk2.default.yellow(` ${prefix}${this.formatTokens(this.callInputTokens)}`)
4920
+ import_chalk.default.dim("out:") + import_chalk.default.yellow(` ${prefix}${this.formatTokens(this.callInputTokens)}`)
4894
4921
  );
4895
4922
  }
4896
4923
  if (outTokens > 0) {
4897
4924
  const prefix = outEstimated ? "~" : "";
4898
- parts.push(import_chalk2.default.dim("in:") + import_chalk2.default.green(` ${prefix}${this.formatTokens(outTokens)}`));
4925
+ parts.push(import_chalk.default.dim("in:") + import_chalk.default.green(` ${prefix}${this.formatTokens(outTokens)}`));
4899
4926
  }
4900
- parts.push(import_chalk2.default.dim(`${elapsed}s`));
4927
+ parts.push(import_chalk.default.dim(`${elapsed}s`));
4901
4928
  } else {
4902
4929
  const elapsed = Math.round((Date.now() - this.totalStartTime) / 1e3);
4903
4930
  if (this.totalTokens > 0) {
4904
- parts.push(import_chalk2.default.magenta(this.formatTokens(this.totalTokens)));
4931
+ parts.push(import_chalk.default.magenta(this.formatTokens(this.totalTokens)));
4905
4932
  }
4906
4933
  if (this.iterations > 0) {
4907
- parts.push(import_chalk2.default.blue(`i${this.iterations}`));
4934
+ parts.push(import_chalk.default.blue(`i${this.iterations}`));
4908
4935
  }
4909
- parts.push(import_chalk2.default.dim(`${elapsed}s`));
4936
+ if (this.totalCost > 0) {
4937
+ parts.push(import_chalk.default.cyan(`$${this.formatCost(this.totalCost)}`));
4938
+ }
4939
+ parts.push(import_chalk.default.dim(`${elapsed}s`));
4910
4940
  }
4911
- return `${parts.join(import_chalk2.default.dim(" \u2502 "))} ${import_chalk2.default.green(">")} `;
4941
+ return `${parts.join(import_chalk.default.dim(" \u2502 "))} ${import_chalk.default.green(">")} `;
4912
4942
  }
4913
4943
  /**
4914
4944
  * Formats token count compactly (3625 -> "3.6k").
@@ -4916,6 +4946,21 @@ var StreamProgress = class {
4916
4946
  formatTokens(tokens) {
4917
4947
  return tokens >= 1e3 ? `${(tokens / 1e3).toFixed(1)}k` : `${tokens}`;
4918
4948
  }
4949
+ /**
4950
+ * Formats cost compactly (0.0001234 -> "0.00012", 0.1234 -> "0.12", 1.234 -> "1.23").
4951
+ */
4952
+ formatCost(cost) {
4953
+ if (cost < 1e-3) {
4954
+ return cost.toFixed(5);
4955
+ }
4956
+ if (cost < 0.01) {
4957
+ return cost.toFixed(4);
4958
+ }
4959
+ if (cost < 1) {
4960
+ return cost.toFixed(3);
4961
+ }
4962
+ return cost.toFixed(2);
4963
+ }
4919
4964
  };
4920
4965
  async function readStream(stream2) {
4921
4966
  const chunks = [];
@@ -4947,29 +4992,42 @@ async function resolvePrompt(promptArg, env) {
4947
4992
  function renderSummary(metadata) {
4948
4993
  const parts = [];
4949
4994
  if (metadata.iterations !== void 0) {
4950
- parts.push(import_chalk2.default.dim(`iterations: ${metadata.iterations}`));
4995
+ parts.push(import_chalk.default.dim(`iterations: ${metadata.iterations}`));
4951
4996
  }
4952
4997
  if (metadata.finishReason) {
4953
- parts.push(import_chalk2.default.dim(`finish: ${metadata.finishReason}`));
4998
+ parts.push(import_chalk.default.dim(`finish: ${metadata.finishReason}`));
4954
4999
  }
4955
5000
  if (metadata.usage) {
4956
5001
  const { inputTokens, outputTokens, totalTokens } = metadata.usage;
4957
5002
  parts.push(
4958
- import_chalk2.default.dim(`tokens: `) + import_chalk2.default.cyan(`${totalTokens}`) + import_chalk2.default.dim(` (in: ${inputTokens}, out: ${outputTokens})`)
5003
+ import_chalk.default.dim(`tokens: `) + import_chalk.default.cyan(`${totalTokens}`) + import_chalk.default.dim(` (in: ${inputTokens}, out: ${outputTokens})`)
4959
5004
  );
4960
5005
  }
5006
+ if (metadata.cost !== void 0 && metadata.cost > 0) {
5007
+ let formattedCost;
5008
+ if (metadata.cost < 1e-3) {
5009
+ formattedCost = metadata.cost.toFixed(5);
5010
+ } else if (metadata.cost < 0.01) {
5011
+ formattedCost = metadata.cost.toFixed(4);
5012
+ } else if (metadata.cost < 1) {
5013
+ formattedCost = metadata.cost.toFixed(3);
5014
+ } else {
5015
+ formattedCost = metadata.cost.toFixed(2);
5016
+ }
5017
+ parts.push(import_chalk.default.dim(`cost: `) + import_chalk.default.cyan(`$${formattedCost}`));
5018
+ }
4961
5019
  if (parts.length === 0) {
4962
5020
  return null;
4963
5021
  }
4964
- return `${import_chalk2.default.dim("\u2500".repeat(40))}
4965
- ${parts.join(import_chalk2.default.dim(" \u2502 "))}`;
5022
+ return `${import_chalk.default.dim("\u2500".repeat(40))}
5023
+ ${parts.join(import_chalk.default.dim(" \u2502 "))}`;
4966
5024
  }
4967
5025
  async function executeAction(action, env) {
4968
5026
  try {
4969
5027
  await action();
4970
5028
  } catch (error) {
4971
5029
  const message = error instanceof Error ? error.message : String(error);
4972
- env.stderr.write(`${import_chalk2.default.red.bold("Error:")} ${message}
5030
+ env.stderr.write(`${import_chalk.default.red.bold("Error:")} ${message}
4973
5031
  `);
4974
5032
  env.setExitCode(1);
4975
5033
  }
@@ -5013,17 +5071,18 @@ ${statsPrompt}` : statsPrompt;
5013
5071
  };
5014
5072
  }
5015
5073
  function formatGadgetSummary(result) {
5016
- const gadgetLabel = import_chalk3.default.magenta.bold(result.gadgetName);
5017
- const timeLabel = import_chalk3.default.dim(`${Math.round(result.executionTimeMs)}ms`);
5074
+ const gadgetLabel = import_chalk2.default.magenta.bold(result.gadgetName);
5075
+ const timeLabel = import_chalk2.default.dim(`${Math.round(result.executionTimeMs)}ms`);
5018
5076
  if (result.error) {
5019
- return `${import_chalk3.default.red("\u2717")} ${gadgetLabel} ${import_chalk3.default.red("error:")} ${result.error} ${timeLabel}`;
5077
+ return `${import_chalk2.default.red("\u2717")} ${gadgetLabel} ${import_chalk2.default.red("error:")} ${result.error} ${timeLabel}`;
5020
5078
  }
5021
5079
  if (result.breaksLoop) {
5022
- return `${import_chalk3.default.yellow("\u23F9")} ${gadgetLabel} ${import_chalk3.default.yellow("finished:")} ${result.result} ${timeLabel}`;
5080
+ return `${import_chalk2.default.yellow("\u23F9")} ${gadgetLabel} ${import_chalk2.default.yellow("finished:")} ${result.result} ${timeLabel}`;
5023
5081
  }
5024
5082
  const maxLen = 80;
5025
- const resultText = result.result ? result.result.length > maxLen ? `${result.result.slice(0, maxLen)}...` : result.result : "";
5026
- return `${import_chalk3.default.green("\u2713")} ${gadgetLabel} ${import_chalk3.default.dim("\u2192")} ${resultText} ${timeLabel}`;
5083
+ const shouldTruncate = result.gadgetName !== "TellUser";
5084
+ const resultText = result.result ? shouldTruncate && result.result.length > maxLen ? `${result.result.slice(0, maxLen)}...` : result.result : "";
5085
+ return `${import_chalk2.default.green("\u2713")} ${gadgetLabel} ${import_chalk2.default.dim("\u2192")} ${resultText} ${timeLabel}`;
5027
5086
  }
5028
5087
  async function handleAgentCommand(promptArg, options, env) {
5029
5088
  const prompt = await resolvePrompt(promptArg, env);
@@ -5043,7 +5102,7 @@ async function handleAgentCommand(promptArg, options, env) {
5043
5102
  }
5044
5103
  const printer = new StreamPrinter(env.stdout);
5045
5104
  const stderrTTY = env.stderr.isTTY === true;
5046
- const progress = new StreamProgress(env.stderr, stderrTTY);
5105
+ const progress = new StreamProgress(env.stderr, stderrTTY, client.modelRegistry);
5047
5106
  let finishReason;
5048
5107
  let usage;
5049
5108
  let iterations = 0;
@@ -5100,16 +5159,25 @@ async function handleAgentCommand(promptArg, options, env) {
5100
5159
  printer.write(event.content);
5101
5160
  } else if (event.type === "gadget_result") {
5102
5161
  progress.pause();
5103
- env.stderr.write(`${formatGadgetSummary(event.result)}
5162
+ if (stderrTTY) {
5163
+ env.stderr.write(`${formatGadgetSummary(event.result)}
5104
5164
  `);
5165
+ }
5105
5166
  }
5106
5167
  }
5107
5168
  progress.complete();
5108
5169
  printer.ensureNewline();
5109
- const summary = renderSummary({ finishReason, usage, iterations });
5110
- if (summary) {
5111
- env.stderr.write(`${summary}
5170
+ if (stderrTTY) {
5171
+ const summary = renderSummary({
5172
+ finishReason,
5173
+ usage,
5174
+ iterations,
5175
+ cost: progress.getTotalCost()
5176
+ });
5177
+ if (summary) {
5178
+ env.stderr.write(`${summary}
5112
5179
  `);
5180
+ }
5113
5181
  }
5114
5182
  }
5115
5183
  function registerAgentCommand(program, env) {
@@ -5138,26 +5206,28 @@ function registerAgentCommand(program, env) {
5138
5206
 
5139
5207
  // src/cli/complete-command.ts
5140
5208
  init_messages();
5209
+ init_model_shortcuts();
5141
5210
  init_constants2();
5142
5211
  async function handleCompleteCommand(promptArg, options, env) {
5143
5212
  const prompt = await resolvePrompt(promptArg, env);
5144
5213
  const client = env.createClient();
5214
+ const model = resolveModel(options.model);
5145
5215
  const builder = new LLMMessageBuilder();
5146
5216
  if (options.system) {
5147
5217
  builder.addSystem(options.system);
5148
5218
  }
5149
5219
  builder.addUser(prompt);
5150
5220
  const stream2 = client.stream({
5151
- model: options.model,
5221
+ model,
5152
5222
  messages: builder.build(),
5153
5223
  temperature: options.temperature,
5154
5224
  maxTokens: options.maxTokens
5155
5225
  });
5156
5226
  const printer = new StreamPrinter(env.stdout);
5157
5227
  const stderrTTY = env.stderr.isTTY === true;
5158
- const progress = new StreamProgress(env.stderr, stderrTTY);
5228
+ const progress = new StreamProgress(env.stderr, stderrTTY, client.modelRegistry);
5159
5229
  const estimatedInputTokens = Math.round(prompt.length / FALLBACK_CHARS_PER_TOKEN);
5160
- progress.startCall(options.model, estimatedInputTokens);
5230
+ progress.startCall(model, estimatedInputTokens);
5161
5231
  let finishReason;
5162
5232
  let usage;
5163
5233
  let totalChars = 0;
@@ -5181,12 +5251,15 @@ async function handleCompleteCommand(promptArg, options, env) {
5181
5251
  finishReason = chunk.finishReason;
5182
5252
  }
5183
5253
  }
5254
+ progress.endCall(usage);
5184
5255
  progress.complete();
5185
5256
  printer.ensureNewline();
5186
- const summary = renderSummary({ finishReason, usage });
5187
- if (summary) {
5188
- env.stderr.write(`${summary}
5257
+ if (stderrTTY) {
5258
+ const summary = renderSummary({ finishReason, usage, cost: progress.getTotalCost() });
5259
+ if (summary) {
5260
+ env.stderr.write(`${summary}
5189
5261
  `);
5262
+ }
5190
5263
  }
5191
5264
  }
5192
5265
  function registerCompleteCommand(program, env) {
@@ -5208,7 +5281,7 @@ function registerCompleteCommand(program, env) {
5208
5281
 
5209
5282
  // src/cli/environment.ts
5210
5283
  var import_node_readline = __toESM(require("readline"), 1);
5211
- var import_chalk4 = __toESM(require("chalk"), 1);
5284
+ var import_chalk3 = __toESM(require("chalk"), 1);
5212
5285
  init_client();
5213
5286
  init_logger();
5214
5287
  var LOG_LEVEL_MAP = {
@@ -5254,14 +5327,14 @@ function createPromptFunction(stdin, stdout) {
5254
5327
  output: stdout
5255
5328
  });
5256
5329
  stdout.write("\n");
5257
- stdout.write(`${import_chalk4.default.cyan("\u2500".repeat(60))}
5330
+ stdout.write(`${import_chalk3.default.cyan("\u2500".repeat(60))}
5258
5331
  `);
5259
- stdout.write(import_chalk4.default.cyan.bold("\u{1F916} Agent asks:\n"));
5332
+ stdout.write(import_chalk3.default.cyan.bold("\u{1F916} Agent asks:\n"));
5260
5333
  stdout.write(`${question}
5261
5334
  `);
5262
- stdout.write(`${import_chalk4.default.cyan("\u2500".repeat(60))}
5335
+ stdout.write(`${import_chalk3.default.cyan("\u2500".repeat(60))}
5263
5336
  `);
5264
- rl.question(import_chalk4.default.green.bold("You: "), (answer) => {
5337
+ rl.question(import_chalk3.default.green.bold("You: "), (answer) => {
5265
5338
  rl.close();
5266
5339
  resolve(answer);
5267
5340
  });