llmist 3.0.0 → 3.1.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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-NBPKLSXJ.js";
2
+ import "./chunk-LFI4WQVV.js";
3
3
  import {
4
4
  AbstractGadget,
5
5
  AgentBuilder,
@@ -34,7 +34,7 @@ import {
34
34
  schemaToJSONSchema,
35
35
  text,
36
36
  validateGadgetSchema
37
- } from "./chunk-67MMSOAT.js";
37
+ } from "./chunk-JCFPJMRQ.js";
38
38
 
39
39
  // src/cli/constants.ts
40
40
  var CLI_NAME = "llmist";
@@ -3113,7 +3113,9 @@ function formatMediaLine(media) {
3113
3113
  }
3114
3114
  function formatGadgetSummary2(result) {
3115
3115
  const gadgetLabel = chalk3.magenta.bold(result.gadgetName);
3116
- const timeLabel = chalk3.dim(`${Math.round(result.executionTimeMs)}ms`);
3116
+ const timeLabel = chalk3.dim(
3117
+ result.executionTimeMs >= 1e3 ? `${(result.executionTimeMs / 1e3).toFixed(1)}s` : `${Math.round(result.executionTimeMs)}ms`
3118
+ );
3117
3119
  const paramsStr = formatParametersInline(result.parameters);
3118
3120
  const paramsLabel = paramsStr ? `${chalk3.dim("(")}${paramsStr}${chalk3.dim(")")}` : "";
3119
3121
  if (result.error) {
@@ -3281,6 +3283,8 @@ var StreamProgress = class {
3281
3283
  delayTimeout = null;
3282
3284
  isRunning = false;
3283
3285
  hasRendered = false;
3286
+ lastRenderLineCount = 0;
3287
+ // Track lines rendered for multi-line clearing
3284
3288
  // Current call stats (streaming mode)
3285
3289
  mode = "cumulative";
3286
3290
  model = "";
@@ -3300,6 +3304,99 @@ var StreamProgress = class {
3300
3304
  totalCost = 0;
3301
3305
  iterations = 0;
3302
3306
  currentIteration = 0;
3307
+ // In-flight gadget tracking for concurrent status display
3308
+ inFlightGadgets = /* @__PURE__ */ new Map();
3309
+ // Nested agent tracking for hierarchical subagent display
3310
+ nestedAgents = /* @__PURE__ */ new Map();
3311
+ // Nested gadget tracking for hierarchical subagent display
3312
+ nestedGadgets = /* @__PURE__ */ new Map();
3313
+ /**
3314
+ * Add a gadget to the in-flight tracking (called when gadget_call event received).
3315
+ * Triggers re-render to show the gadget in the status display.
3316
+ */
3317
+ addGadget(invocationId, name, params) {
3318
+ this.inFlightGadgets.set(invocationId, { name, params, startTime: Date.now() });
3319
+ if (this.isRunning && this.isTTY) {
3320
+ this.render();
3321
+ }
3322
+ }
3323
+ /**
3324
+ * Remove a gadget from in-flight tracking (called when gadget_result event received).
3325
+ * Triggers re-render to update the status display.
3326
+ */
3327
+ removeGadget(invocationId) {
3328
+ this.inFlightGadgets.delete(invocationId);
3329
+ if (this.isRunning && this.isTTY) {
3330
+ this.render();
3331
+ }
3332
+ }
3333
+ /**
3334
+ * Check if there are any gadgets currently in flight.
3335
+ */
3336
+ hasInFlightGadgets() {
3337
+ return this.inFlightGadgets.size > 0;
3338
+ }
3339
+ /**
3340
+ * Add a nested agent LLM call (called when nested llm_call_start event received).
3341
+ * Used to display hierarchical progress for subagent gadgets.
3342
+ */
3343
+ addNestedAgent(id, parentInvocationId, depth, model, iteration, inputTokens) {
3344
+ this.nestedAgents.set(id, {
3345
+ parentInvocationId,
3346
+ depth,
3347
+ model,
3348
+ iteration,
3349
+ startTime: Date.now(),
3350
+ inputTokens
3351
+ });
3352
+ if (this.isRunning && this.isTTY) {
3353
+ this.render();
3354
+ }
3355
+ }
3356
+ /**
3357
+ * Update a nested agent with completion info (called when nested llm_call_end event received).
3358
+ */
3359
+ updateNestedAgent(id, outputTokens) {
3360
+ const agent = this.nestedAgents.get(id);
3361
+ if (agent) {
3362
+ agent.outputTokens = outputTokens;
3363
+ if (this.isRunning && this.isTTY) {
3364
+ this.render();
3365
+ }
3366
+ }
3367
+ }
3368
+ /**
3369
+ * Remove a nested agent (called when the nested LLM call completes).
3370
+ */
3371
+ removeNestedAgent(id) {
3372
+ this.nestedAgents.delete(id);
3373
+ if (this.isRunning && this.isTTY) {
3374
+ this.render();
3375
+ }
3376
+ }
3377
+ /**
3378
+ * Add a nested gadget call (called when nested gadget_call event received).
3379
+ */
3380
+ addNestedGadget(id, depth, parentInvocationId, name) {
3381
+ this.nestedGadgets.set(id, {
3382
+ depth,
3383
+ parentInvocationId,
3384
+ name,
3385
+ startTime: Date.now()
3386
+ });
3387
+ if (this.isRunning && this.isTTY) {
3388
+ this.render();
3389
+ }
3390
+ }
3391
+ /**
3392
+ * Remove a nested gadget (called when nested gadget_result event received).
3393
+ */
3394
+ removeNestedGadget(id) {
3395
+ this.nestedGadgets.delete(id);
3396
+ if (this.isRunning && this.isTTY) {
3397
+ this.render();
3398
+ }
3399
+ }
3303
3400
  /**
3304
3401
  * Starts a new LLM call. Switches to streaming mode.
3305
3402
  * @param model - Model name being used
@@ -3426,15 +3523,57 @@ var StreamProgress = class {
3426
3523
  this.isStreaming = true;
3427
3524
  }
3428
3525
  render() {
3526
+ this.clearRenderedLines();
3429
3527
  const spinner = SPINNER_FRAMES[this.frameIndex++ % SPINNER_FRAMES.length];
3528
+ const lines = [];
3430
3529
  if (this.mode === "streaming") {
3431
- this.renderStreamingMode(spinner);
3530
+ lines.push(this.formatStreamingLine(spinner));
3432
3531
  } else {
3433
- this.renderCumulativeMode(spinner);
3532
+ lines.push(this.formatCumulativeLine(spinner));
3533
+ }
3534
+ if (this.isTTY) {
3535
+ for (const [gadgetId, gadget] of this.inFlightGadgets) {
3536
+ const elapsed = ((Date.now() - gadget.startTime) / 1e3).toFixed(1);
3537
+ const gadgetLine = ` ${chalk4.blue("\u23F5")} ${chalk4.magenta.bold(gadget.name)}${chalk4.dim("(...)")} ${chalk4.dim(elapsed + "s")}`;
3538
+ lines.push(gadgetLine);
3539
+ for (const [_agentId, nested] of this.nestedAgents) {
3540
+ if (nested.parentInvocationId !== gadgetId) continue;
3541
+ const indent = " ".repeat(nested.depth + 1);
3542
+ const nestedElapsed = ((Date.now() - nested.startTime) / 1e3).toFixed(1);
3543
+ const tokens = nested.inputTokens ? ` ${chalk4.dim("\u2191")}${chalk4.yellow(formatTokens(nested.inputTokens))}` : "";
3544
+ const outTokens = nested.outputTokens ? ` ${chalk4.dim("\u2193")}${chalk4.green(formatTokens(nested.outputTokens))}` : "";
3545
+ const nestedLine = `${indent}${chalk4.cyan(`#${nested.iteration}`)} ${chalk4.dim(nested.model)}${tokens}${outTokens} ${chalk4.dim(nestedElapsed + "s")} ${chalk4.cyan(spinner)}`;
3546
+ lines.push(nestedLine);
3547
+ }
3548
+ for (const [_nestedId, nestedGadget] of this.nestedGadgets) {
3549
+ if (nestedGadget.parentInvocationId === gadgetId) {
3550
+ const indent = " ".repeat(nestedGadget.depth + 1);
3551
+ const nestedElapsed = ((Date.now() - nestedGadget.startTime) / 1e3).toFixed(1);
3552
+ const nestedGadgetLine = `${indent}${chalk4.blue("\u23F5")} ${chalk4.dim(nestedGadget.name + "(...)")} ${chalk4.dim(nestedElapsed + "s")}`;
3553
+ lines.push(nestedGadgetLine);
3554
+ }
3555
+ }
3556
+ }
3434
3557
  }
3558
+ this.lastRenderLineCount = lines.length;
3559
+ this.target.write("\r" + lines.join("\n"));
3435
3560
  this.hasRendered = true;
3436
3561
  }
3437
- renderStreamingMode(spinner) {
3562
+ /**
3563
+ * Clears the previously rendered lines (for multi-line status display).
3564
+ */
3565
+ clearRenderedLines() {
3566
+ if (!this.hasRendered || this.lastRenderLineCount === 0) return;
3567
+ this.target.write("\r\x1B[K");
3568
+ for (let i = 1; i < this.lastRenderLineCount; i++) {
3569
+ this.target.write("\x1B[1A\x1B[K");
3570
+ }
3571
+ this.target.write("\r");
3572
+ }
3573
+ /**
3574
+ * Format the streaming mode progress line (returns string, doesn't write).
3575
+ */
3576
+ formatStreamingLine(spinner) {
3438
3577
  const elapsed = ((Date.now() - this.callStartTime) / 1e3).toFixed(1);
3439
3578
  const outTokens = this.callOutputTokensEstimated ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN) : this.callOutputTokens;
3440
3579
  const parts = [];
@@ -3468,7 +3607,7 @@ var StreamProgress = class {
3468
3607
  if (callCost > 0) {
3469
3608
  parts.push(chalk4.cyan(`$${formatCost(callCost)}`));
3470
3609
  }
3471
- this.target.write(`\r${parts.join(chalk4.dim(" | "))} ${chalk4.cyan(spinner)}`);
3610
+ return `${parts.join(chalk4.dim(" | "))} ${chalk4.cyan(spinner)}`;
3472
3611
  }
3473
3612
  /**
3474
3613
  * Calculates live cost estimate for the current streaming call.
@@ -3505,7 +3644,10 @@ var StreamProgress = class {
3505
3644
  }
3506
3645
  return this.callInputTokens / limits.contextWindow * 100;
3507
3646
  }
3508
- renderCumulativeMode(spinner) {
3647
+ /**
3648
+ * Format the cumulative mode progress line (returns string, doesn't write).
3649
+ */
3650
+ formatCumulativeLine(spinner) {
3509
3651
  const elapsed = ((Date.now() - this.totalStartTime) / 1e3).toFixed(1);
3510
3652
  const parts = [];
3511
3653
  if (this.model) {
@@ -3521,10 +3663,10 @@ var StreamProgress = class {
3521
3663
  parts.push(chalk4.dim("cost:") + chalk4.cyan(` $${formatCost(this.totalCost)}`));
3522
3664
  }
3523
3665
  parts.push(chalk4.dim(`${elapsed}s`));
3524
- this.target.write(`\r${parts.join(chalk4.dim(" | "))} ${chalk4.cyan(spinner)}`);
3666
+ return `${parts.join(chalk4.dim(" | "))} ${chalk4.cyan(spinner)}`;
3525
3667
  }
3526
3668
  /**
3527
- * Pauses the progress indicator and clears the line.
3669
+ * Pauses the progress indicator and clears all rendered lines.
3528
3670
  * Can be resumed with start().
3529
3671
  */
3530
3672
  pause() {
@@ -3538,10 +3680,9 @@ var StreamProgress = class {
3538
3680
  this.interval = null;
3539
3681
  }
3540
3682
  this.isRunning = false;
3541
- if (this.hasRendered) {
3542
- this.target.write("\r\x1B[K\x1B[0G");
3543
- this.hasRendered = false;
3544
- }
3683
+ this.clearRenderedLines();
3684
+ this.hasRendered = false;
3685
+ this.lastRenderLineCount = 0;
3545
3686
  }
3546
3687
  /**
3547
3688
  * Completes the progress indicator and clears the line.
@@ -4118,6 +4259,38 @@ Denied: ${result.reason ?? "by user"}`
4118
4259
  "Maximize efficiency by batching independent operations in a single response."
4119
4260
  ].join(" ")
4120
4261
  );
4262
+ if (!options.quiet) {
4263
+ builder.withNestedEventCallback((event) => {
4264
+ if (event.type === "llm_call_start") {
4265
+ const info = event.event;
4266
+ const nestedId = `${event.gadgetInvocationId}:${info.iteration}`;
4267
+ progress.addNestedAgent(
4268
+ nestedId,
4269
+ event.gadgetInvocationId,
4270
+ event.depth,
4271
+ info.model,
4272
+ info.iteration,
4273
+ info.inputTokens
4274
+ );
4275
+ } else if (event.type === "llm_call_end") {
4276
+ const info = event.event;
4277
+ const nestedId = `${event.gadgetInvocationId}:${info.iteration}`;
4278
+ progress.updateNestedAgent(nestedId, info.outputTokens);
4279
+ setTimeout(() => progress.removeNestedAgent(nestedId), 100);
4280
+ } else if (event.type === "gadget_call") {
4281
+ const gadgetEvent = event.event;
4282
+ progress.addNestedGadget(
4283
+ gadgetEvent.call.invocationId,
4284
+ event.depth,
4285
+ event.gadgetInvocationId,
4286
+ gadgetEvent.call.gadgetName
4287
+ );
4288
+ } else if (event.type === "gadget_result") {
4289
+ const resultEvent = event.event;
4290
+ progress.removeNestedGadget(resultEvent.result.invocationId);
4291
+ }
4292
+ });
4293
+ }
4121
4294
  let agent;
4122
4295
  if (options.image || options.audio) {
4123
4296
  const parts = [text(prompt)];
@@ -4142,10 +4315,22 @@ Denied: ${result.reason ?? "by user"}`
4142
4315
  try {
4143
4316
  for await (const event of agent.run()) {
4144
4317
  if (event.type === "text") {
4145
- progress.pause();
4146
4318
  textBuffer += event.content;
4319
+ } else if (event.type === "gadget_call") {
4320
+ flushTextBuffer();
4321
+ if (!options.quiet) {
4322
+ progress.addGadget(
4323
+ event.call.invocationId,
4324
+ event.call.gadgetName,
4325
+ event.call.parameters
4326
+ );
4327
+ progress.start();
4328
+ }
4147
4329
  } else if (event.type === "gadget_result") {
4148
4330
  flushTextBuffer();
4331
+ if (!options.quiet) {
4332
+ progress.removeGadget(event.result.invocationId);
4333
+ }
4149
4334
  progress.pause();
4150
4335
  if (options.quiet) {
4151
4336
  if (event.result.gadgetName === "TellUser" && event.result.parameters?.message) {
@@ -4160,6 +4345,9 @@ Denied: ${result.reason ?? "by user"}`
4160
4345
  `
4161
4346
  );
4162
4347
  }
4348
+ if (progress.hasInFlightGadgets()) {
4349
+ progress.start();
4350
+ }
4163
4351
  }
4164
4352
  }
4165
4353
  } catch (error) {