llmist 5.0.0 → 5.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.cjs CHANGED
@@ -9479,13 +9479,24 @@ ${endPrefix}`
9479
9479
  observers: {
9480
9480
  ...hooks?.observers,
9481
9481
  onLLMCallStart: async (context) => {
9482
+ let inputTokens;
9483
+ try {
9484
+ if (this.client) {
9485
+ inputTokens = await this.client.countTokens(
9486
+ context.options.model,
9487
+ context.options.messages
9488
+ );
9489
+ }
9490
+ } catch {
9491
+ }
9482
9492
  onSubagentEvent({
9483
9493
  type: "llm_call_start",
9484
9494
  gadgetInvocationId: invocationId,
9485
9495
  depth,
9486
9496
  event: {
9487
9497
  iteration: context.iteration,
9488
- model: context.options.model
9498
+ model: context.options.model,
9499
+ inputTokens
9489
9500
  }
9490
9501
  });
9491
9502
  if (existingOnLLMCallStart) {
@@ -9958,7 +9969,7 @@ var import_commander2 = require("commander");
9958
9969
  // package.json
9959
9970
  var package_default = {
9960
9971
  name: "llmist",
9961
- version: "5.0.0",
9972
+ version: "5.1.0",
9962
9973
  description: "TypeScript LLM client with streaming tool execution. Tools fire mid-stream. Built-in function calling works with any model\u2014no structured outputs or native tool support required.",
9963
9974
  type: "module",
9964
9975
  main: "dist/index.cjs",
@@ -12954,7 +12965,7 @@ function getRawValue(value) {
12954
12965
  function truncateValue(str, maxLen) {
12955
12966
  if (maxLen <= 0) return "";
12956
12967
  if (str.length <= maxLen) return str;
12957
- return `${str.slice(0, maxLen)}\u2026`;
12968
+ return `${str.slice(0, maxLen - 1)}\u2026`;
12958
12969
  }
12959
12970
  function formatParametersInline(params, maxWidth) {
12960
12971
  if (!params || Object.keys(params).length === 0) {
@@ -12982,6 +12993,11 @@ function formatParametersInline(params, maxWidth) {
12982
12993
  const proportion = v.length / totalRawLength;
12983
12994
  return Math.max(minPerValue, Math.floor(proportion * availableForValues));
12984
12995
  });
12996
+ const totalLimits = limits.reduce((sum, l) => sum + l, 0);
12997
+ if (totalLimits > availableForValues) {
12998
+ const scale = availableForValues / totalLimits;
12999
+ limits = limits.map((l) => Math.max(1, Math.floor(l * scale)));
13000
+ }
12985
13001
  }
12986
13002
  }
12987
13003
  } else {
@@ -12997,8 +13013,8 @@ function formatGadgetLine(info, maxWidth) {
12997
13013
  const gadgetLabel = import_chalk3.default.magenta.bold(info.name);
12998
13014
  const timeStr = `${info.elapsedSeconds.toFixed(1)}s`;
12999
13015
  const timeLabel = import_chalk3.default.dim(timeStr);
13000
- const fixedLength = 2 + info.name.length + 2 + 1 + timeStr.length;
13001
- const availableForParams = Math.max(40, terminalWidth - fixedLength - 2);
13016
+ const fixedLength = 3 + info.name.length + 2 + 1 + timeStr.length;
13017
+ const availableForParams = Math.max(40, terminalWidth - fixedLength - 3);
13002
13018
  const paramsStr = formatParametersInline(info.parameters, availableForParams);
13003
13019
  const paramsLabel = paramsStr ? `${import_chalk3.default.dim("(")}${paramsStr}${import_chalk3.default.dim(")")}` : "";
13004
13020
  if (info.error) {
@@ -13008,17 +13024,21 @@ function formatGadgetLine(info, maxWidth) {
13008
13024
  if (!info.isComplete) {
13009
13025
  return `${import_chalk3.default.blue("\u23F5")} ${gadgetLabel}${paramsLabel} ${timeLabel}`;
13010
13026
  }
13011
- let outputStr;
13027
+ let outputLabel;
13012
13028
  if (info.tokenCount !== void 0 && info.tokenCount > 0) {
13013
- outputStr = `${formatTokens(info.tokenCount)} tokens`;
13029
+ outputLabel = import_chalk3.default.dim("\u2193") + import_chalk3.default.green(` ${formatTokens(info.tokenCount)} `);
13014
13030
  } else if (info.outputBytes !== void 0 && info.outputBytes > 0) {
13015
- outputStr = formatBytes(info.outputBytes);
13031
+ outputLabel = import_chalk3.default.green(formatBytes(info.outputBytes)) + " ";
13016
13032
  } else {
13017
- outputStr = "";
13033
+ outputLabel = "";
13018
13034
  }
13019
13035
  const icon = info.breaksLoop ? import_chalk3.default.yellow("\u23F9") : import_chalk3.default.green("\u2713");
13020
- const outputLabel = outputStr ? ` ${import_chalk3.default.dim("\u2192")} ${import_chalk3.default.green(outputStr)}` : "";
13021
- return `${icon} ${gadgetLabel}${paramsLabel}${outputLabel} ${timeLabel}`;
13036
+ const nameRef = import_chalk3.default.magenta(info.name);
13037
+ const line1 = `${icon} ${gadgetLabel}${paramsLabel}`;
13038
+ const line2Prefix = ` ${import_chalk3.default.dim("\u2192")} ${nameRef} ${outputLabel}`;
13039
+ const line2 = `${line2Prefix}${timeLabel}`;
13040
+ return `${line1}
13041
+ ${line2}`;
13022
13042
  }
13023
13043
  function formatBytes(bytes) {
13024
13044
  if (bytes < 1024) {
@@ -13029,6 +13049,11 @@ function formatBytes(bytes) {
13029
13049
  }
13030
13050
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
13031
13051
  }
13052
+ function truncateOutputPreview(output, maxWidth) {
13053
+ const normalized = output.replace(/\s+/g, " ").trim();
13054
+ if (normalized.length <= maxWidth) return normalized;
13055
+ return normalized.slice(0, maxWidth - 1) + "\u2026";
13056
+ }
13032
13057
  function getMediaIcon(kind) {
13033
13058
  switch (kind) {
13034
13059
  case "image":
@@ -13056,37 +13081,99 @@ function formatGadgetSummary2(result) {
13056
13081
  const gadgetLabel = import_chalk3.default.magenta.bold(result.gadgetName);
13057
13082
  const timeStr = result.executionTimeMs >= 1e3 ? `${(result.executionTimeMs / 1e3).toFixed(1)}s` : `${Math.round(result.executionTimeMs)}ms`;
13058
13083
  const timeLabel = import_chalk3.default.dim(timeStr);
13059
- let outputStr;
13060
- if (result.tokenCount !== void 0 && result.tokenCount > 0) {
13061
- outputStr = `${formatTokens(result.tokenCount)} tokens`;
13062
- } else if (result.result) {
13084
+ const fixedLength = 3 + result.gadgetName.length + 2;
13085
+ const availableForParams = Math.max(40, terminalWidth - fixedLength - 3);
13086
+ const paramsStr = formatParametersInline(result.parameters, availableForParams);
13087
+ const paramsLabel = paramsStr ? `${import_chalk3.default.dim("(")}${paramsStr}${import_chalk3.default.dim(")")}` : "";
13088
+ const icon = result.breaksLoop ? import_chalk3.default.yellow("\u23F9") : result.error ? import_chalk3.default.red("\u2717") : import_chalk3.default.green("\u2713");
13089
+ const line1 = `${icon} ${gadgetLabel}${paramsLabel}`;
13090
+ const nameRef = import_chalk3.default.magenta(result.gadgetName);
13091
+ const hasSubagentMetrics = result.subagentMetrics && result.subagentMetrics.callCount > 0;
13092
+ let outputLabel;
13093
+ let outputStrRaw;
13094
+ if (!hasSubagentMetrics && result.tokenCount !== void 0 && result.tokenCount > 0) {
13095
+ const tokenStr = formatTokens(result.tokenCount);
13096
+ outputLabel = import_chalk3.default.dim("\u2193") + import_chalk3.default.green(` ${tokenStr} `);
13097
+ outputStrRaw = `\u2193 ${tokenStr} `;
13098
+ } else if (!hasSubagentMetrics && result.result) {
13063
13099
  const outputBytes = Buffer.byteLength(result.result, "utf-8");
13064
- outputStr = outputBytes > 0 ? formatBytes(outputBytes) : "no output";
13100
+ if (outputBytes > 0) {
13101
+ const bytesStr = formatBytes(outputBytes);
13102
+ outputLabel = import_chalk3.default.green(bytesStr) + " ";
13103
+ outputStrRaw = bytesStr + " ";
13104
+ } else {
13105
+ outputLabel = "";
13106
+ outputStrRaw = "";
13107
+ }
13065
13108
  } else {
13066
- outputStr = "no output";
13109
+ outputLabel = "";
13110
+ outputStrRaw = "";
13067
13111
  }
13068
- const fixedLength = 2 + result.gadgetName.length + 2 + 3 + outputStr.length + 1 + timeStr.length;
13069
- const availableForParams = Math.max(40, terminalWidth - fixedLength - 2);
13070
- const paramsStr = formatParametersInline(result.parameters, availableForParams);
13071
- const paramsLabel = paramsStr ? `${import_chalk3.default.dim("(")}${paramsStr}${import_chalk3.default.dim(")")}` : "";
13072
13112
  if (result.error) {
13073
13113
  const errorMsg = result.error.length > 50 ? `${result.error.slice(0, 50)}\u2026` : result.error;
13074
- return `${import_chalk3.default.red("\u2717")} ${gadgetLabel}${paramsLabel} ${import_chalk3.default.red("error:")} ${errorMsg} ${timeLabel}`;
13114
+ const line22 = ` ${import_chalk3.default.dim("\u2192")} ${nameRef} ${import_chalk3.default.red("error:")} ${errorMsg} ${timeLabel}`;
13115
+ return `${line1}
13116
+ ${line22}`;
13117
+ }
13118
+ const previewWidth = Math.floor(terminalWidth * 0.6);
13119
+ const prefixLength = 4 + result.gadgetName.length + 1 + outputStrRaw.length + 1 + timeStr.length + 2;
13120
+ const availablePreview = Math.max(20, previewWidth - prefixLength);
13121
+ let customPreview;
13122
+ if (result.gadgetName === "TodoUpsert" && result.parameters?.content) {
13123
+ const statusEmoji = result.parameters.status === "done" ? "\u2705" : result.parameters.status === "in_progress" ? "\u{1F504}" : "\u2B1C";
13124
+ const content = String(result.parameters.content);
13125
+ customPreview = `${statusEmoji} ${truncateOutputPreview(content, availablePreview - 3)}`;
13126
+ }
13127
+ if (result.gadgetName === "GoogleSearch" && result.parameters?.query) {
13128
+ const query = String(result.parameters.query);
13129
+ const countMatch = result.result?.match(/\((\d+)\s+of\s+[\d,]+\s+results?\)/i) || // "(10 of 36400000 results)"
13130
+ result.result?.match(/(\d+)\s+results?\s+found/i) || // "10 results found"
13131
+ result.result?.match(/found\s+(\d+)\s+results?/i);
13132
+ const count = countMatch?.[1] ?? (result.parameters.maxResults ? String(result.parameters.maxResults) : null);
13133
+ const countStr = count ? ` \u2192 ${count} results` : "";
13134
+ const queryPreview = truncateOutputPreview(query, availablePreview - 5 - countStr.length);
13135
+ customPreview = `\u{1F50D} "${queryPreview}"${countStr}`;
13136
+ }
13137
+ let subagentMetricsStr = "";
13138
+ if (result.subagentMetrics && result.subagentMetrics.callCount > 0) {
13139
+ const parts = [];
13140
+ const m = result.subagentMetrics;
13141
+ if (m.inputTokens > 0) {
13142
+ parts.push(import_chalk3.default.dim("\u2191") + import_chalk3.default.yellow(` ${formatTokens(m.inputTokens)}`));
13143
+ }
13144
+ if (m.cachedInputTokens > 0) {
13145
+ parts.push(import_chalk3.default.dim("\u27F3") + import_chalk3.default.blue(` ${formatTokens(m.cachedInputTokens)}`));
13146
+ }
13147
+ if (m.outputTokens > 0) {
13148
+ parts.push(import_chalk3.default.dim("\u2193") + import_chalk3.default.green(` ${formatTokens(m.outputTokens)}`));
13149
+ }
13150
+ if (m.cost > 0) {
13151
+ parts.push(import_chalk3.default.cyan(`$${formatCost(m.cost)}`));
13152
+ }
13153
+ if (parts.length > 0) {
13154
+ subagentMetricsStr = parts.join(import_chalk3.default.dim(" | ")) + import_chalk3.default.dim(" | ");
13155
+ }
13075
13156
  }
13076
- const outputLabel = outputStr === "no output" ? import_chalk3.default.dim(outputStr) : import_chalk3.default.green(outputStr);
13077
- const icon = result.breaksLoop ? import_chalk3.default.yellow("\u23F9") : import_chalk3.default.green("\u2713");
13078
- let summaryLine = `${icon} ${gadgetLabel}${paramsLabel} ${import_chalk3.default.dim("\u2192")} ${outputLabel} ${timeLabel}`;
13157
+ let line2;
13158
+ const previewContent = customPreview ?? (result.result?.trim() ? truncateOutputPreview(result.result, availablePreview) : null);
13159
+ if (previewContent) {
13160
+ line2 = ` ${import_chalk3.default.dim("\u2192")} ${nameRef} ${outputLabel}${subagentMetricsStr}${timeLabel}${import_chalk3.default.dim(":")} ${import_chalk3.default.dim(previewContent)}`;
13161
+ } else {
13162
+ line2 = ` ${import_chalk3.default.dim("\u2192")} ${nameRef} ${outputLabel}${subagentMetricsStr}${timeLabel}`;
13163
+ }
13164
+ let output = `${line1}
13165
+ ${line2}`;
13079
13166
  if (result.media && result.media.length > 0) {
13080
13167
  const mediaLines = result.media.map(formatMediaLine);
13081
- summaryLine += "\n" + mediaLines.join("\n");
13168
+ output += "\n" + mediaLines.join("\n");
13082
13169
  }
13083
13170
  if (result.gadgetName === "TellUser" && result.parameters?.message) {
13084
13171
  const message = String(result.parameters.message);
13085
13172
  const rendered = renderMarkdownWithSeparators(message);
13086
- return `${summaryLine}
13173
+ return `${output}
13087
13174
  ${rendered}`;
13088
13175
  }
13089
- return summaryLine;
13176
+ return output;
13090
13177
  }
13091
13178
 
13092
13179
  // src/cli/utils.ts
@@ -13283,14 +13370,15 @@ var StreamProgress = class {
13283
13370
  * Add a nested agent LLM call (called when nested llm_call_start event received).
13284
13371
  * Used to display hierarchical progress for subagent gadgets.
13285
13372
  */
13286
- addNestedAgent(id, parentInvocationId, depth, model, iteration, inputTokens) {
13373
+ addNestedAgent(id, parentInvocationId, depth, model, iteration, info) {
13287
13374
  this.nestedAgents.set(id, {
13288
13375
  parentInvocationId,
13289
13376
  depth,
13290
13377
  model,
13291
13378
  iteration,
13292
13379
  startTime: Date.now(),
13293
- inputTokens
13380
+ inputTokens: info?.inputTokens,
13381
+ cachedInputTokens: info?.cachedInputTokens
13294
13382
  });
13295
13383
  if (this.isRunning && this.isTTY) {
13296
13384
  this.render();
@@ -13304,22 +13392,23 @@ var StreamProgress = class {
13304
13392
  updateNestedAgent(id, info) {
13305
13393
  const agent = this.nestedAgents.get(id);
13306
13394
  if (agent) {
13307
- agent.inputTokens = info.inputTokens;
13308
- agent.outputTokens = info.outputTokens;
13309
- agent.cachedInputTokens = info.cachedInputTokens;
13310
- agent.cacheCreationInputTokens = info.cacheCreationInputTokens;
13311
- agent.finishReason = info.finishReason;
13395
+ if (info.inputTokens !== void 0) agent.inputTokens = info.inputTokens;
13396
+ if (info.outputTokens !== void 0) agent.outputTokens = info.outputTokens;
13397
+ if (info.cachedInputTokens !== void 0) agent.cachedInputTokens = info.cachedInputTokens;
13398
+ if (info.cacheCreationInputTokens !== void 0)
13399
+ agent.cacheCreationInputTokens = info.cacheCreationInputTokens;
13400
+ if (info.finishReason !== void 0) agent.finishReason = info.finishReason;
13312
13401
  if (info.cost !== void 0) {
13313
13402
  agent.cost = info.cost;
13314
- } else if (this.modelRegistry && agent.model && info.outputTokens) {
13403
+ } else if (this.modelRegistry && agent.model && agent.outputTokens) {
13315
13404
  try {
13316
13405
  const modelName = agent.model.includes(":") ? agent.model.split(":")[1] : agent.model;
13317
13406
  const costResult = this.modelRegistry.estimateCost(
13318
13407
  modelName,
13319
- info.inputTokens ?? 0,
13320
- info.outputTokens,
13321
- info.cachedInputTokens,
13322
- info.cacheCreationInputTokens
13408
+ agent.inputTokens ?? 0,
13409
+ agent.outputTokens,
13410
+ agent.cachedInputTokens,
13411
+ agent.cacheCreationInputTokens
13323
13412
  );
13324
13413
  agent.cost = costResult?.totalCost;
13325
13414
  } catch {
@@ -13341,6 +13430,27 @@ var StreamProgress = class {
13341
13430
  this.render();
13342
13431
  }
13343
13432
  }
13433
+ /**
13434
+ * Get aggregated metrics from all nested agents for a parent gadget.
13435
+ * Used to show total token counts and cost for subagent gadgets like BrowseWeb.
13436
+ */
13437
+ getAggregatedSubagentMetrics(parentInvocationId) {
13438
+ let inputTokens = 0;
13439
+ let outputTokens = 0;
13440
+ let cachedInputTokens = 0;
13441
+ let cost = 0;
13442
+ let callCount = 0;
13443
+ for (const [, nested] of this.nestedAgents) {
13444
+ if (nested.parentInvocationId === parentInvocationId) {
13445
+ inputTokens += nested.inputTokens ?? 0;
13446
+ outputTokens += nested.outputTokens ?? 0;
13447
+ cachedInputTokens += nested.cachedInputTokens ?? 0;
13448
+ cost += nested.cost ?? 0;
13449
+ callCount++;
13450
+ }
13451
+ }
13452
+ return { inputTokens, outputTokens, cachedInputTokens, cost, callCount };
13453
+ }
13344
13454
  /**
13345
13455
  * Add a nested gadget call (called when nested gadget_call event received).
13346
13456
  */
@@ -13508,20 +13618,22 @@ var StreamProgress = class {
13508
13618
  this.clearRenderedLines();
13509
13619
  const spinner = SPINNER_FRAMES[this.frameIndex++ % SPINNER_FRAMES.length];
13510
13620
  const lines = [];
13511
- if (this.mode === "streaming") {
13512
- lines.push(this.formatStreamingLine(spinner));
13513
- } else {
13514
- lines.push(this.formatCumulativeLine(spinner));
13515
- }
13621
+ const activeNestedStreams = [];
13516
13622
  if (this.isTTY) {
13517
13623
  for (const [gadgetId, gadget] of this.inFlightGadgets) {
13518
13624
  const elapsedSeconds = (Date.now() - gadget.startTime) / 1e3;
13519
- const gadgetLine = ` ${formatGadgetLine({
13520
- name: gadget.name,
13521
- parameters: gadget.params,
13522
- elapsedSeconds,
13523
- isComplete: false
13524
- })}`;
13625
+ const termWidth = process.stdout.columns ?? 80;
13626
+ const gadgetIndent = " ";
13627
+ const line = formatGadgetLine(
13628
+ {
13629
+ name: gadget.name,
13630
+ parameters: gadget.params,
13631
+ elapsedSeconds,
13632
+ isComplete: false
13633
+ },
13634
+ termWidth - gadgetIndent.length
13635
+ );
13636
+ const gadgetLine = line.split("\n").map((l) => gadgetIndent + l).join("\n");
13525
13637
  lines.push(gadgetLine);
13526
13638
  const nestedOps = [];
13527
13639
  for (const [_agentId, nested] of this.nestedAgents) {
@@ -13540,6 +13652,18 @@ var StreamProgress = class {
13540
13652
  completed: nested.completed,
13541
13653
  completedTime: nested.completedTime
13542
13654
  });
13655
+ if (!nested.completed) {
13656
+ activeNestedStreams.push({
13657
+ depth: nested.depth,
13658
+ iteration: nested.iteration,
13659
+ model: nested.model,
13660
+ inputTokens: nested.inputTokens,
13661
+ cachedInputTokens: nested.cachedInputTokens,
13662
+ outputTokens: nested.outputTokens,
13663
+ cost: nested.cost,
13664
+ startTime: nested.startTime
13665
+ });
13666
+ }
13543
13667
  }
13544
13668
  }
13545
13669
  for (const [_nestedId, nestedGadget] of this.nestedGadgets) {
@@ -13557,11 +13681,14 @@ var StreamProgress = class {
13557
13681
  }
13558
13682
  nestedOps.sort((a, b) => a.startTime - b.startTime);
13559
13683
  for (const op of nestedOps) {
13560
- const indent = " ".repeat(op.depth + 1);
13684
+ if (op.type === "agent" && !op.completed) {
13685
+ continue;
13686
+ }
13687
+ const indent = " ".repeat(op.depth + 2);
13561
13688
  const endTime = op.completedTime ?? Date.now();
13562
13689
  const elapsedSeconds2 = (endTime - op.startTime) / 1e3;
13563
13690
  if (op.type === "agent") {
13564
- const line = formatLLMCallLine({
13691
+ const line2 = formatLLMCallLine({
13565
13692
  iteration: op.iteration ?? 0,
13566
13693
  model: op.model ?? "",
13567
13694
  inputTokens: op.inputTokens,
@@ -13573,21 +13700,48 @@ var StreamProgress = class {
13573
13700
  isStreaming: !op.completed,
13574
13701
  spinner
13575
13702
  });
13576
- lines.push(`${indent}${line}`);
13703
+ lines.push(`${indent}${line2}`);
13577
13704
  } else {
13578
- const line = formatGadgetLine({
13579
- name: op.name ?? "",
13580
- parameters: op.parameters,
13581
- elapsedSeconds: elapsedSeconds2,
13582
- isComplete: op.completed ?? false
13583
- });
13584
- lines.push(`${indent}${line}`);
13705
+ const termWidth2 = process.stdout.columns ?? 80;
13706
+ const line2 = formatGadgetLine(
13707
+ {
13708
+ name: op.name ?? "",
13709
+ parameters: op.parameters,
13710
+ elapsedSeconds: elapsedSeconds2,
13711
+ isComplete: op.completed ?? false
13712
+ },
13713
+ termWidth2 - indent.length
13714
+ );
13715
+ const indentedLine = line2.split("\n").map((l) => indent + l).join("\n");
13716
+ lines.push(indentedLine);
13585
13717
  }
13586
13718
  }
13587
13719
  }
13588
13720
  }
13589
- this.lastRenderLineCount = lines.length;
13590
- this.target.write("\r" + lines.join("\n"));
13721
+ for (const stream2 of activeNestedStreams) {
13722
+ const indent = " ".repeat(stream2.depth + 2);
13723
+ const elapsedSeconds = (Date.now() - stream2.startTime) / 1e3;
13724
+ const line = formatLLMCallLine({
13725
+ iteration: stream2.iteration,
13726
+ model: stream2.model,
13727
+ inputTokens: stream2.inputTokens,
13728
+ cachedInputTokens: stream2.cachedInputTokens,
13729
+ outputTokens: stream2.outputTokens,
13730
+ elapsedSeconds,
13731
+ cost: stream2.cost,
13732
+ isStreaming: true,
13733
+ spinner
13734
+ });
13735
+ lines.push(`${indent}${line}`);
13736
+ }
13737
+ if (this.mode === "streaming") {
13738
+ lines.push(this.formatStreamingLine(spinner));
13739
+ } else {
13740
+ lines.push(this.formatCumulativeLine(spinner));
13741
+ }
13742
+ const output = lines.join("\n");
13743
+ this.lastRenderLineCount = (output.match(/\n/g) || []).length + 1;
13744
+ this.target.write("\r" + output);
13591
13745
  this.hasRendered = true;
13592
13746
  }
13593
13747
  /**
@@ -14199,6 +14353,7 @@ async function executeAgent(promptArg, options, env) {
14199
14353
  env.stderr.write(`${summary}
14200
14354
  `);
14201
14355
  }
14356
+ env.stderr.write("\n");
14202
14357
  }
14203
14358
  if (llmSessionDir) {
14204
14359
  const filename = `${formatCallNumber(llmCallCounter)}.response`;
@@ -14305,8 +14460,7 @@ Denied: ${result.reason ?? "by user"}`
14305
14460
  builder.withTrailingMessage(
14306
14461
  (ctx) => [
14307
14462
  `[Iteration ${ctx.iteration + 1}/${ctx.maxIterations}]`,
14308
- "Think carefully: what gadget invocations can you make in parallel right now?",
14309
- "Maximize efficiency by batching independent operations in a single response."
14463
+ "Think carefully in two steps: 1. what gadget invocations we should be making next? 2. how do they depend on one another so we can run all of them in the right order? Then respond with all the gadget invocations you are able to do now."
14310
14464
  ].join(" ")
14311
14465
  );
14312
14466
  if (!options.quiet) {
@@ -14319,8 +14473,12 @@ Denied: ${result.reason ?? "by user"}`
14319
14473
  subagentEvent.gadgetInvocationId,
14320
14474
  subagentEvent.depth,
14321
14475
  info.model,
14322
- info.iteration,
14323
- info.inputTokens
14476
+ info.iteration + 1,
14477
+ // Make 1-indexed like main agent
14478
+ {
14479
+ inputTokens: info.usage?.inputTokens ?? info.inputTokens,
14480
+ cachedInputTokens: info.usage?.cachedInputTokens
14481
+ }
14324
14482
  );
14325
14483
  } else if (subagentEvent.type === "llm_call_end") {
14326
14484
  const info = subagentEvent.event;
@@ -14397,10 +14555,23 @@ Denied: ${result.reason ?? "by user"}`
14397
14555
  }
14398
14556
  } else {
14399
14557
  const tokenCount = await countGadgetOutputTokens(event.result.result);
14400
- env.stderr.write(
14401
- `${formatGadgetSummary2({ ...event.result, tokenCount, media: event.result.storedMedia })}
14402
- `
14558
+ const subagentMetrics = progress.getAggregatedSubagentMetrics(
14559
+ event.result.invocationId
14403
14560
  );
14561
+ const summary = formatGadgetSummary2({
14562
+ ...event.result,
14563
+ tokenCount,
14564
+ media: event.result.storedMedia,
14565
+ subagentMetrics: subagentMetrics.callCount > 0 ? subagentMetrics : void 0
14566
+ });
14567
+ if (event.result.gadgetName === "TellUser") {
14568
+ env.stderr.write(`${summary}
14569
+ `);
14570
+ } else {
14571
+ const indentedSummary = summary.split("\n").map((line) => " " + line).join("\n");
14572
+ env.stderr.write(`${indentedSummary}
14573
+ `);
14574
+ }
14404
14575
  }
14405
14576
  if (progress.hasInFlightGadgets()) {
14406
14577
  progress.start();