llmist 5.0.0 → 6.0.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/{chunk-3SZIQI45.js → chunk-EIE5VRSI.js} +72 -7
- package/dist/chunk-EIE5VRSI.js.map +1 -0
- package/dist/{chunk-UBPZUVIN.js → chunk-F62X5W2G.js} +2 -2
- package/dist/cli.cjs +360 -83
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +288 -76
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +71 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +2 -2
- package/dist/testing/index.cjs +71 -6
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-3SZIQI45.js.map +0 -1
- /package/dist/{chunk-UBPZUVIN.js.map → chunk-F62X5W2G.js.map} +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -3870,6 +3870,8 @@ var init_stream_processor = __esm({
|
|
|
3870
3870
|
completedResults = /* @__PURE__ */ new Map();
|
|
3871
3871
|
/** Invocation IDs of gadgets that have failed (error or skipped due to dependency) */
|
|
3872
3872
|
failedInvocations = /* @__PURE__ */ new Set();
|
|
3873
|
+
/** Promises for independent gadgets currently executing (fire-and-forget) */
|
|
3874
|
+
inFlightExecutions = /* @__PURE__ */ new Map();
|
|
3873
3875
|
constructor(options) {
|
|
3874
3876
|
this.iteration = options.iteration;
|
|
3875
3877
|
this.registry = options.registry;
|
|
@@ -3978,6 +3980,16 @@ var init_stream_processor = __esm({
|
|
|
3978
3980
|
}
|
|
3979
3981
|
}
|
|
3980
3982
|
}
|
|
3983
|
+
const inFlightResults = await this.collectInFlightResults();
|
|
3984
|
+
for (const evt of inFlightResults) {
|
|
3985
|
+
yield evt;
|
|
3986
|
+
if (evt.type === "gadget_result") {
|
|
3987
|
+
didExecuteGadgets = true;
|
|
3988
|
+
if (evt.result.breaksLoop) {
|
|
3989
|
+
shouldBreakLoop = true;
|
|
3990
|
+
}
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3981
3993
|
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
3982
3994
|
yield evt;
|
|
3983
3995
|
if (evt.type === "gadget_result") {
|
|
@@ -4163,12 +4175,24 @@ var init_stream_processor = __esm({
|
|
|
4163
4175
|
this.gadgetsAwaitingDependencies.set(call.invocationId, call);
|
|
4164
4176
|
return;
|
|
4165
4177
|
}
|
|
4178
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4179
|
+
yield evt;
|
|
4180
|
+
}
|
|
4181
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
4182
|
+
yield evt;
|
|
4183
|
+
}
|
|
4184
|
+
return;
|
|
4166
4185
|
}
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4186
|
+
if (this.stopOnGadgetError) {
|
|
4187
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4188
|
+
yield evt;
|
|
4189
|
+
}
|
|
4190
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
4191
|
+
yield evt;
|
|
4192
|
+
}
|
|
4193
|
+
} else {
|
|
4194
|
+
const executionPromise = this.executeGadgetAndCollect(call);
|
|
4195
|
+
this.inFlightExecutions.set(call.invocationId, executionPromise);
|
|
4172
4196
|
}
|
|
4173
4197
|
}
|
|
4174
4198
|
/**
|
|
@@ -4480,6 +4504,36 @@ var init_stream_processor = __esm({
|
|
|
4480
4504
|
}
|
|
4481
4505
|
}
|
|
4482
4506
|
}
|
|
4507
|
+
/**
|
|
4508
|
+
* Execute a gadget and collect all events into an array (non-blocking).
|
|
4509
|
+
* Used for fire-and-forget parallel execution of independent gadgets.
|
|
4510
|
+
*/
|
|
4511
|
+
async executeGadgetAndCollect(call) {
|
|
4512
|
+
const events = [];
|
|
4513
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4514
|
+
events.push(evt);
|
|
4515
|
+
}
|
|
4516
|
+
return events;
|
|
4517
|
+
}
|
|
4518
|
+
/**
|
|
4519
|
+
* Collect results from all fire-and-forget (in-flight) gadget executions.
|
|
4520
|
+
* Called at stream end to await parallel independent gadgets.
|
|
4521
|
+
* Clears the inFlightExecutions map after collection.
|
|
4522
|
+
* @returns Array of all events from completed gadgets
|
|
4523
|
+
*/
|
|
4524
|
+
async collectInFlightResults() {
|
|
4525
|
+
if (this.inFlightExecutions.size === 0) {
|
|
4526
|
+
return [];
|
|
4527
|
+
}
|
|
4528
|
+
this.logger.debug("Collecting in-flight gadget results", {
|
|
4529
|
+
count: this.inFlightExecutions.size,
|
|
4530
|
+
invocationIds: Array.from(this.inFlightExecutions.keys())
|
|
4531
|
+
});
|
|
4532
|
+
const promises = Array.from(this.inFlightExecutions.values());
|
|
4533
|
+
const results = await Promise.all(promises);
|
|
4534
|
+
this.inFlightExecutions.clear();
|
|
4535
|
+
return results.flat();
|
|
4536
|
+
}
|
|
4483
4537
|
/**
|
|
4484
4538
|
* Handle a gadget that cannot execute because a dependency failed.
|
|
4485
4539
|
* Calls the onDependencySkipped controller to allow customization.
|
|
@@ -9479,13 +9533,24 @@ ${endPrefix}`
|
|
|
9479
9533
|
observers: {
|
|
9480
9534
|
...hooks?.observers,
|
|
9481
9535
|
onLLMCallStart: async (context) => {
|
|
9536
|
+
let inputTokens;
|
|
9537
|
+
try {
|
|
9538
|
+
if (this.client) {
|
|
9539
|
+
inputTokens = await this.client.countTokens(
|
|
9540
|
+
context.options.model,
|
|
9541
|
+
context.options.messages
|
|
9542
|
+
);
|
|
9543
|
+
}
|
|
9544
|
+
} catch {
|
|
9545
|
+
}
|
|
9482
9546
|
onSubagentEvent({
|
|
9483
9547
|
type: "llm_call_start",
|
|
9484
9548
|
gadgetInvocationId: invocationId,
|
|
9485
9549
|
depth,
|
|
9486
9550
|
event: {
|
|
9487
9551
|
iteration: context.iteration,
|
|
9488
|
-
model: context.options.model
|
|
9552
|
+
model: context.options.model,
|
|
9553
|
+
inputTokens
|
|
9489
9554
|
}
|
|
9490
9555
|
});
|
|
9491
9556
|
if (existingOnLLMCallStart) {
|
|
@@ -9958,7 +10023,7 @@ var import_commander2 = require("commander");
|
|
|
9958
10023
|
// package.json
|
|
9959
10024
|
var package_default = {
|
|
9960
10025
|
name: "llmist",
|
|
9961
|
-
version: "5.
|
|
10026
|
+
version: "5.1.0",
|
|
9962
10027
|
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
10028
|
type: "module",
|
|
9964
10029
|
main: "dist/index.cjs",
|
|
@@ -12849,7 +12914,8 @@ function formatCost(cost) {
|
|
|
12849
12914
|
}
|
|
12850
12915
|
function formatLLMCallLine(info) {
|
|
12851
12916
|
const parts = [];
|
|
12852
|
-
|
|
12917
|
+
const callNumber = info.parentCallNumber ? `#${info.parentCallNumber}.${info.iteration}` : `#${info.iteration}`;
|
|
12918
|
+
parts.push(`${import_chalk3.default.cyan(callNumber)} ${import_chalk3.default.magenta(info.model)}`);
|
|
12853
12919
|
if (info.contextPercent !== void 0 && info.contextPercent !== null) {
|
|
12854
12920
|
const formatted = `${Math.round(info.contextPercent)}%`;
|
|
12855
12921
|
if (info.contextPercent >= 80) {
|
|
@@ -12954,7 +13020,7 @@ function getRawValue(value) {
|
|
|
12954
13020
|
function truncateValue(str, maxLen) {
|
|
12955
13021
|
if (maxLen <= 0) return "";
|
|
12956
13022
|
if (str.length <= maxLen) return str;
|
|
12957
|
-
return `${str.slice(0, maxLen)}\u2026`;
|
|
13023
|
+
return `${str.slice(0, maxLen - 1)}\u2026`;
|
|
12958
13024
|
}
|
|
12959
13025
|
function formatParametersInline(params, maxWidth) {
|
|
12960
13026
|
if (!params || Object.keys(params).length === 0) {
|
|
@@ -12982,6 +13048,11 @@ function formatParametersInline(params, maxWidth) {
|
|
|
12982
13048
|
const proportion = v.length / totalRawLength;
|
|
12983
13049
|
return Math.max(minPerValue, Math.floor(proportion * availableForValues));
|
|
12984
13050
|
});
|
|
13051
|
+
const totalLimits = limits.reduce((sum, l) => sum + l, 0);
|
|
13052
|
+
if (totalLimits > availableForValues) {
|
|
13053
|
+
const scale = availableForValues / totalLimits;
|
|
13054
|
+
limits = limits.map((l) => Math.max(1, Math.floor(l * scale)));
|
|
13055
|
+
}
|
|
12985
13056
|
}
|
|
12986
13057
|
}
|
|
12987
13058
|
} else {
|
|
@@ -12997,8 +13068,8 @@ function formatGadgetLine(info, maxWidth) {
|
|
|
12997
13068
|
const gadgetLabel = import_chalk3.default.magenta.bold(info.name);
|
|
12998
13069
|
const timeStr = `${info.elapsedSeconds.toFixed(1)}s`;
|
|
12999
13070
|
const timeLabel = import_chalk3.default.dim(timeStr);
|
|
13000
|
-
const fixedLength =
|
|
13001
|
-
const availableForParams = Math.max(40, terminalWidth - fixedLength -
|
|
13071
|
+
const fixedLength = 3 + info.name.length + 2 + 1 + timeStr.length;
|
|
13072
|
+
const availableForParams = Math.max(40, terminalWidth - fixedLength - 3);
|
|
13002
13073
|
const paramsStr = formatParametersInline(info.parameters, availableForParams);
|
|
13003
13074
|
const paramsLabel = paramsStr ? `${import_chalk3.default.dim("(")}${paramsStr}${import_chalk3.default.dim(")")}` : "";
|
|
13004
13075
|
if (info.error) {
|
|
@@ -13008,17 +13079,21 @@ function formatGadgetLine(info, maxWidth) {
|
|
|
13008
13079
|
if (!info.isComplete) {
|
|
13009
13080
|
return `${import_chalk3.default.blue("\u23F5")} ${gadgetLabel}${paramsLabel} ${timeLabel}`;
|
|
13010
13081
|
}
|
|
13011
|
-
let
|
|
13082
|
+
let outputLabel;
|
|
13012
13083
|
if (info.tokenCount !== void 0 && info.tokenCount > 0) {
|
|
13013
|
-
|
|
13084
|
+
outputLabel = import_chalk3.default.dim("\u2193") + import_chalk3.default.green(` ${formatTokens(info.tokenCount)} `);
|
|
13014
13085
|
} else if (info.outputBytes !== void 0 && info.outputBytes > 0) {
|
|
13015
|
-
|
|
13086
|
+
outputLabel = import_chalk3.default.green(formatBytes(info.outputBytes)) + " ";
|
|
13016
13087
|
} else {
|
|
13017
|
-
|
|
13088
|
+
outputLabel = "";
|
|
13018
13089
|
}
|
|
13019
13090
|
const icon = info.breaksLoop ? import_chalk3.default.yellow("\u23F9") : import_chalk3.default.green("\u2713");
|
|
13020
|
-
const
|
|
13021
|
-
|
|
13091
|
+
const nameRef = import_chalk3.default.magenta(info.name);
|
|
13092
|
+
const line1 = `${icon} ${gadgetLabel}${paramsLabel}`;
|
|
13093
|
+
const line2Prefix = ` ${import_chalk3.default.dim("\u2192")} ${nameRef} ${outputLabel}`;
|
|
13094
|
+
const line2 = `${line2Prefix}${timeLabel}`;
|
|
13095
|
+
return `${line1}
|
|
13096
|
+
${line2}`;
|
|
13022
13097
|
}
|
|
13023
13098
|
function formatBytes(bytes) {
|
|
13024
13099
|
if (bytes < 1024) {
|
|
@@ -13029,6 +13104,11 @@ function formatBytes(bytes) {
|
|
|
13029
13104
|
}
|
|
13030
13105
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
13031
13106
|
}
|
|
13107
|
+
function truncateOutputPreview(output, maxWidth) {
|
|
13108
|
+
const normalized = output.replace(/\s+/g, " ").trim();
|
|
13109
|
+
if (normalized.length <= maxWidth) return normalized;
|
|
13110
|
+
return normalized.slice(0, maxWidth - 1) + "\u2026";
|
|
13111
|
+
}
|
|
13032
13112
|
function getMediaIcon(kind) {
|
|
13033
13113
|
switch (kind) {
|
|
13034
13114
|
case "image":
|
|
@@ -13056,37 +13136,99 @@ function formatGadgetSummary2(result) {
|
|
|
13056
13136
|
const gadgetLabel = import_chalk3.default.magenta.bold(result.gadgetName);
|
|
13057
13137
|
const timeStr = result.executionTimeMs >= 1e3 ? `${(result.executionTimeMs / 1e3).toFixed(1)}s` : `${Math.round(result.executionTimeMs)}ms`;
|
|
13058
13138
|
const timeLabel = import_chalk3.default.dim(timeStr);
|
|
13059
|
-
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13139
|
+
const fixedLength = 3 + result.gadgetName.length + 2;
|
|
13140
|
+
const availableForParams = Math.max(40, terminalWidth - fixedLength - 3);
|
|
13141
|
+
const paramsStr = formatParametersInline(result.parameters, availableForParams);
|
|
13142
|
+
const paramsLabel = paramsStr ? `${import_chalk3.default.dim("(")}${paramsStr}${import_chalk3.default.dim(")")}` : "";
|
|
13143
|
+
const icon = result.breaksLoop ? import_chalk3.default.yellow("\u23F9") : result.error ? import_chalk3.default.red("\u2717") : import_chalk3.default.green("\u2713");
|
|
13144
|
+
const line1 = `${icon} ${gadgetLabel}${paramsLabel}`;
|
|
13145
|
+
const nameRef = import_chalk3.default.magenta(result.gadgetName);
|
|
13146
|
+
const hasSubagentMetrics = result.subagentMetrics && result.subagentMetrics.callCount > 0;
|
|
13147
|
+
let outputLabel;
|
|
13148
|
+
let outputStrRaw;
|
|
13149
|
+
if (!hasSubagentMetrics && result.tokenCount !== void 0 && result.tokenCount > 0) {
|
|
13150
|
+
const tokenStr = formatTokens(result.tokenCount);
|
|
13151
|
+
outputLabel = import_chalk3.default.dim("\u2193") + import_chalk3.default.green(` ${tokenStr} `);
|
|
13152
|
+
outputStrRaw = `\u2193 ${tokenStr} `;
|
|
13153
|
+
} else if (!hasSubagentMetrics && result.result) {
|
|
13063
13154
|
const outputBytes = Buffer.byteLength(result.result, "utf-8");
|
|
13064
|
-
|
|
13155
|
+
if (outputBytes > 0) {
|
|
13156
|
+
const bytesStr = formatBytes(outputBytes);
|
|
13157
|
+
outputLabel = import_chalk3.default.green(bytesStr) + " ";
|
|
13158
|
+
outputStrRaw = bytesStr + " ";
|
|
13159
|
+
} else {
|
|
13160
|
+
outputLabel = "";
|
|
13161
|
+
outputStrRaw = "";
|
|
13162
|
+
}
|
|
13065
13163
|
} else {
|
|
13066
|
-
|
|
13164
|
+
outputLabel = "";
|
|
13165
|
+
outputStrRaw = "";
|
|
13067
13166
|
}
|
|
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
13167
|
if (result.error) {
|
|
13073
13168
|
const errorMsg = result.error.length > 50 ? `${result.error.slice(0, 50)}\u2026` : result.error;
|
|
13074
|
-
|
|
13169
|
+
const line22 = ` ${import_chalk3.default.dim("\u2192")} ${nameRef} ${import_chalk3.default.red("error:")} ${errorMsg} ${timeLabel}`;
|
|
13170
|
+
return `${line1}
|
|
13171
|
+
${line22}`;
|
|
13172
|
+
}
|
|
13173
|
+
const previewWidth = Math.floor(terminalWidth * 0.6);
|
|
13174
|
+
const prefixLength = 4 + result.gadgetName.length + 1 + outputStrRaw.length + 1 + timeStr.length + 2;
|
|
13175
|
+
const availablePreview = Math.max(20, previewWidth - prefixLength);
|
|
13176
|
+
let customPreview;
|
|
13177
|
+
if (result.gadgetName === "TodoUpsert" && result.parameters?.content) {
|
|
13178
|
+
const statusEmoji = result.parameters.status === "done" ? "\u2705" : result.parameters.status === "in_progress" ? "\u{1F504}" : "\u2B1C";
|
|
13179
|
+
const content = String(result.parameters.content);
|
|
13180
|
+
customPreview = `${statusEmoji} ${truncateOutputPreview(content, availablePreview - 3)}`;
|
|
13181
|
+
}
|
|
13182
|
+
if (result.gadgetName === "GoogleSearch" && result.parameters?.query) {
|
|
13183
|
+
const query = String(result.parameters.query);
|
|
13184
|
+
const countMatch = result.result?.match(/\((\d+)\s+of\s+[\d,]+\s+results?\)/i) || // "(10 of 36400000 results)"
|
|
13185
|
+
result.result?.match(/(\d+)\s+results?\s+found/i) || // "10 results found"
|
|
13186
|
+
result.result?.match(/found\s+(\d+)\s+results?/i);
|
|
13187
|
+
const count = countMatch?.[1] ?? (result.parameters.maxResults ? String(result.parameters.maxResults) : null);
|
|
13188
|
+
const countStr = count ? ` \u2192 ${count} results` : "";
|
|
13189
|
+
const queryPreview = truncateOutputPreview(query, availablePreview - 5 - countStr.length);
|
|
13190
|
+
customPreview = `\u{1F50D} "${queryPreview}"${countStr}`;
|
|
13191
|
+
}
|
|
13192
|
+
let subagentMetricsStr = "";
|
|
13193
|
+
if (result.subagentMetrics && result.subagentMetrics.callCount > 0) {
|
|
13194
|
+
const parts = [];
|
|
13195
|
+
const m = result.subagentMetrics;
|
|
13196
|
+
if (m.inputTokens > 0) {
|
|
13197
|
+
parts.push(import_chalk3.default.dim("\u2191") + import_chalk3.default.yellow(` ${formatTokens(m.inputTokens)}`));
|
|
13198
|
+
}
|
|
13199
|
+
if (m.cachedInputTokens > 0) {
|
|
13200
|
+
parts.push(import_chalk3.default.dim("\u27F3") + import_chalk3.default.blue(` ${formatTokens(m.cachedInputTokens)}`));
|
|
13201
|
+
}
|
|
13202
|
+
if (m.outputTokens > 0) {
|
|
13203
|
+
parts.push(import_chalk3.default.dim("\u2193") + import_chalk3.default.green(` ${formatTokens(m.outputTokens)}`));
|
|
13204
|
+
}
|
|
13205
|
+
if (m.cost > 0) {
|
|
13206
|
+
parts.push(import_chalk3.default.cyan(`$${formatCost(m.cost)}`));
|
|
13207
|
+
}
|
|
13208
|
+
if (parts.length > 0) {
|
|
13209
|
+
subagentMetricsStr = parts.join(import_chalk3.default.dim(" | ")) + import_chalk3.default.dim(" | ");
|
|
13210
|
+
}
|
|
13211
|
+
}
|
|
13212
|
+
let line2;
|
|
13213
|
+
const previewContent = customPreview ?? (result.result?.trim() ? truncateOutputPreview(result.result, availablePreview) : null);
|
|
13214
|
+
if (previewContent) {
|
|
13215
|
+
line2 = ` ${import_chalk3.default.dim("\u2192")} ${nameRef} ${outputLabel}${subagentMetricsStr}${timeLabel}${import_chalk3.default.dim(":")} ${import_chalk3.default.dim(previewContent)}`;
|
|
13216
|
+
} else {
|
|
13217
|
+
line2 = ` ${import_chalk3.default.dim("\u2192")} ${nameRef} ${outputLabel}${subagentMetricsStr}${timeLabel}`;
|
|
13075
13218
|
}
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
let summaryLine = `${icon} ${gadgetLabel}${paramsLabel} ${import_chalk3.default.dim("\u2192")} ${outputLabel} ${timeLabel}`;
|
|
13219
|
+
let output = `${line1}
|
|
13220
|
+
${line2}`;
|
|
13079
13221
|
if (result.media && result.media.length > 0) {
|
|
13080
13222
|
const mediaLines = result.media.map(formatMediaLine);
|
|
13081
|
-
|
|
13223
|
+
output += "\n" + mediaLines.join("\n");
|
|
13082
13224
|
}
|
|
13083
13225
|
if (result.gadgetName === "TellUser" && result.parameters?.message) {
|
|
13084
13226
|
const message = String(result.parameters.message);
|
|
13085
13227
|
const rendered = renderMarkdownWithSeparators(message);
|
|
13086
|
-
return `${
|
|
13228
|
+
return `${output}
|
|
13087
13229
|
${rendered}`;
|
|
13088
13230
|
}
|
|
13089
|
-
return
|
|
13231
|
+
return output;
|
|
13090
13232
|
}
|
|
13091
13233
|
|
|
13092
13234
|
// src/cli/utils.ts
|
|
@@ -13279,18 +13421,60 @@ var StreamProgress = class {
|
|
|
13279
13421
|
hasInFlightGadgets() {
|
|
13280
13422
|
return this.inFlightGadgets.size > 0;
|
|
13281
13423
|
}
|
|
13424
|
+
/**
|
|
13425
|
+
* Mark a gadget as completed (keeps it visible with ✓ indicator).
|
|
13426
|
+
* Records completion time to freeze the elapsed timer.
|
|
13427
|
+
* The gadget and its nested operations remain visible until clearCompletedGadgets() is called.
|
|
13428
|
+
*/
|
|
13429
|
+
completeGadget(invocationId) {
|
|
13430
|
+
const gadget = this.inFlightGadgets.get(invocationId);
|
|
13431
|
+
if (gadget) {
|
|
13432
|
+
gadget.completed = true;
|
|
13433
|
+
gadget.completedTime = Date.now();
|
|
13434
|
+
if (this.isRunning && this.isTTY) {
|
|
13435
|
+
this.render();
|
|
13436
|
+
}
|
|
13437
|
+
}
|
|
13438
|
+
}
|
|
13439
|
+
/**
|
|
13440
|
+
* Clear all completed gadgets from the display.
|
|
13441
|
+
* Called when new text output arrives to clean up the finished gadget section.
|
|
13442
|
+
*/
|
|
13443
|
+
clearCompletedGadgets() {
|
|
13444
|
+
for (const [id, gadget] of this.inFlightGadgets) {
|
|
13445
|
+
if (gadget.completed) {
|
|
13446
|
+
this.inFlightGadgets.delete(id);
|
|
13447
|
+
for (const [nestedId, nested] of this.nestedAgents) {
|
|
13448
|
+
if (nested.parentInvocationId === id) {
|
|
13449
|
+
this.nestedAgents.delete(nestedId);
|
|
13450
|
+
}
|
|
13451
|
+
}
|
|
13452
|
+
for (const [nestedId, nested] of this.nestedGadgets) {
|
|
13453
|
+
if (nested.parentInvocationId === id) {
|
|
13454
|
+
this.nestedGadgets.delete(nestedId);
|
|
13455
|
+
}
|
|
13456
|
+
}
|
|
13457
|
+
}
|
|
13458
|
+
}
|
|
13459
|
+
if (this.isRunning && this.isTTY) {
|
|
13460
|
+
this.render();
|
|
13461
|
+
}
|
|
13462
|
+
}
|
|
13282
13463
|
/**
|
|
13283
13464
|
* Add a nested agent LLM call (called when nested llm_call_start event received).
|
|
13284
13465
|
* Used to display hierarchical progress for subagent gadgets.
|
|
13466
|
+
* @param parentCallNumber - Top-level call number for hierarchical display (e.g., #1.2)
|
|
13285
13467
|
*/
|
|
13286
|
-
addNestedAgent(id, parentInvocationId, depth, model, iteration,
|
|
13468
|
+
addNestedAgent(id, parentInvocationId, depth, model, iteration, info, parentCallNumber) {
|
|
13287
13469
|
this.nestedAgents.set(id, {
|
|
13288
13470
|
parentInvocationId,
|
|
13289
13471
|
depth,
|
|
13290
13472
|
model,
|
|
13291
13473
|
iteration,
|
|
13474
|
+
parentCallNumber,
|
|
13292
13475
|
startTime: Date.now(),
|
|
13293
|
-
inputTokens
|
|
13476
|
+
inputTokens: info?.inputTokens,
|
|
13477
|
+
cachedInputTokens: info?.cachedInputTokens
|
|
13294
13478
|
});
|
|
13295
13479
|
if (this.isRunning && this.isTTY) {
|
|
13296
13480
|
this.render();
|
|
@@ -13304,22 +13488,23 @@ var StreamProgress = class {
|
|
|
13304
13488
|
updateNestedAgent(id, info) {
|
|
13305
13489
|
const agent = this.nestedAgents.get(id);
|
|
13306
13490
|
if (agent) {
|
|
13307
|
-
agent.inputTokens = info.inputTokens;
|
|
13308
|
-
agent.outputTokens = info.outputTokens;
|
|
13309
|
-
agent.cachedInputTokens = info.cachedInputTokens;
|
|
13310
|
-
|
|
13311
|
-
|
|
13491
|
+
if (info.inputTokens !== void 0) agent.inputTokens = info.inputTokens;
|
|
13492
|
+
if (info.outputTokens !== void 0) agent.outputTokens = info.outputTokens;
|
|
13493
|
+
if (info.cachedInputTokens !== void 0) agent.cachedInputTokens = info.cachedInputTokens;
|
|
13494
|
+
if (info.cacheCreationInputTokens !== void 0)
|
|
13495
|
+
agent.cacheCreationInputTokens = info.cacheCreationInputTokens;
|
|
13496
|
+
if (info.finishReason !== void 0) agent.finishReason = info.finishReason;
|
|
13312
13497
|
if (info.cost !== void 0) {
|
|
13313
13498
|
agent.cost = info.cost;
|
|
13314
|
-
} else if (this.modelRegistry && agent.model &&
|
|
13499
|
+
} else if (this.modelRegistry && agent.model && agent.outputTokens) {
|
|
13315
13500
|
try {
|
|
13316
13501
|
const modelName = agent.model.includes(":") ? agent.model.split(":")[1] : agent.model;
|
|
13317
13502
|
const costResult = this.modelRegistry.estimateCost(
|
|
13318
13503
|
modelName,
|
|
13319
|
-
|
|
13320
|
-
|
|
13321
|
-
|
|
13322
|
-
|
|
13504
|
+
agent.inputTokens ?? 0,
|
|
13505
|
+
agent.outputTokens,
|
|
13506
|
+
agent.cachedInputTokens,
|
|
13507
|
+
agent.cacheCreationInputTokens
|
|
13323
13508
|
);
|
|
13324
13509
|
agent.cost = costResult?.totalCost;
|
|
13325
13510
|
} catch {
|
|
@@ -13341,6 +13526,27 @@ var StreamProgress = class {
|
|
|
13341
13526
|
this.render();
|
|
13342
13527
|
}
|
|
13343
13528
|
}
|
|
13529
|
+
/**
|
|
13530
|
+
* Get aggregated metrics from all nested agents for a parent gadget.
|
|
13531
|
+
* Used to show total token counts and cost for subagent gadgets like BrowseWeb.
|
|
13532
|
+
*/
|
|
13533
|
+
getAggregatedSubagentMetrics(parentInvocationId) {
|
|
13534
|
+
let inputTokens = 0;
|
|
13535
|
+
let outputTokens = 0;
|
|
13536
|
+
let cachedInputTokens = 0;
|
|
13537
|
+
let cost = 0;
|
|
13538
|
+
let callCount = 0;
|
|
13539
|
+
for (const [, nested] of this.nestedAgents) {
|
|
13540
|
+
if (nested.parentInvocationId === parentInvocationId) {
|
|
13541
|
+
inputTokens += nested.inputTokens ?? 0;
|
|
13542
|
+
outputTokens += nested.outputTokens ?? 0;
|
|
13543
|
+
cachedInputTokens += nested.cachedInputTokens ?? 0;
|
|
13544
|
+
cost += nested.cost ?? 0;
|
|
13545
|
+
callCount++;
|
|
13546
|
+
}
|
|
13547
|
+
}
|
|
13548
|
+
return { inputTokens, outputTokens, cachedInputTokens, cost, callCount };
|
|
13549
|
+
}
|
|
13344
13550
|
/**
|
|
13345
13551
|
* Add a nested gadget call (called when nested gadget_call event received).
|
|
13346
13552
|
*/
|
|
@@ -13508,20 +13714,23 @@ var StreamProgress = class {
|
|
|
13508
13714
|
this.clearRenderedLines();
|
|
13509
13715
|
const spinner = SPINNER_FRAMES[this.frameIndex++ % SPINNER_FRAMES.length];
|
|
13510
13716
|
const lines = [];
|
|
13511
|
-
|
|
13512
|
-
lines.push(this.formatStreamingLine(spinner));
|
|
13513
|
-
} else {
|
|
13514
|
-
lines.push(this.formatCumulativeLine(spinner));
|
|
13515
|
-
}
|
|
13717
|
+
const activeNestedStreams = [];
|
|
13516
13718
|
if (this.isTTY) {
|
|
13517
13719
|
for (const [gadgetId, gadget] of this.inFlightGadgets) {
|
|
13518
|
-
const
|
|
13519
|
-
const
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13720
|
+
const endTime = gadget.completedTime ?? Date.now();
|
|
13721
|
+
const elapsedSeconds = (endTime - gadget.startTime) / 1e3;
|
|
13722
|
+
const termWidth = process.stdout.columns ?? 80;
|
|
13723
|
+
const gadgetIndent = " ";
|
|
13724
|
+
const line = formatGadgetLine(
|
|
13725
|
+
{
|
|
13726
|
+
name: gadget.name,
|
|
13727
|
+
parameters: gadget.params,
|
|
13728
|
+
elapsedSeconds,
|
|
13729
|
+
isComplete: gadget.completed ?? false
|
|
13730
|
+
},
|
|
13731
|
+
termWidth - gadgetIndent.length
|
|
13732
|
+
);
|
|
13733
|
+
const gadgetLine = line.split("\n").map((l) => gadgetIndent + l).join("\n");
|
|
13525
13734
|
lines.push(gadgetLine);
|
|
13526
13735
|
const nestedOps = [];
|
|
13527
13736
|
for (const [_agentId, nested] of this.nestedAgents) {
|
|
@@ -13531,6 +13740,7 @@ var StreamProgress = class {
|
|
|
13531
13740
|
startTime: nested.startTime,
|
|
13532
13741
|
depth: nested.depth,
|
|
13533
13742
|
iteration: nested.iteration,
|
|
13743
|
+
parentCallNumber: nested.parentCallNumber,
|
|
13534
13744
|
model: nested.model,
|
|
13535
13745
|
inputTokens: nested.inputTokens,
|
|
13536
13746
|
cachedInputTokens: nested.cachedInputTokens,
|
|
@@ -13540,6 +13750,19 @@ var StreamProgress = class {
|
|
|
13540
13750
|
completed: nested.completed,
|
|
13541
13751
|
completedTime: nested.completedTime
|
|
13542
13752
|
});
|
|
13753
|
+
if (!nested.completed) {
|
|
13754
|
+
activeNestedStreams.push({
|
|
13755
|
+
depth: nested.depth,
|
|
13756
|
+
iteration: nested.iteration,
|
|
13757
|
+
parentCallNumber: nested.parentCallNumber,
|
|
13758
|
+
model: nested.model,
|
|
13759
|
+
inputTokens: nested.inputTokens,
|
|
13760
|
+
cachedInputTokens: nested.cachedInputTokens,
|
|
13761
|
+
outputTokens: nested.outputTokens,
|
|
13762
|
+
cost: nested.cost,
|
|
13763
|
+
startTime: nested.startTime
|
|
13764
|
+
});
|
|
13765
|
+
}
|
|
13543
13766
|
}
|
|
13544
13767
|
}
|
|
13545
13768
|
for (const [_nestedId, nestedGadget] of this.nestedGadgets) {
|
|
@@ -13557,12 +13780,16 @@ var StreamProgress = class {
|
|
|
13557
13780
|
}
|
|
13558
13781
|
nestedOps.sort((a, b) => a.startTime - b.startTime);
|
|
13559
13782
|
for (const op of nestedOps) {
|
|
13560
|
-
|
|
13561
|
-
|
|
13562
|
-
|
|
13783
|
+
if (op.type === "agent" && !op.completed) {
|
|
13784
|
+
continue;
|
|
13785
|
+
}
|
|
13786
|
+
const indent = " ".repeat(op.depth + 2);
|
|
13787
|
+
const endTime2 = op.completedTime ?? Date.now();
|
|
13788
|
+
const elapsedSeconds2 = (endTime2 - op.startTime) / 1e3;
|
|
13563
13789
|
if (op.type === "agent") {
|
|
13564
|
-
const
|
|
13790
|
+
const line2 = formatLLMCallLine({
|
|
13565
13791
|
iteration: op.iteration ?? 0,
|
|
13792
|
+
parentCallNumber: op.parentCallNumber,
|
|
13566
13793
|
model: op.model ?? "",
|
|
13567
13794
|
inputTokens: op.inputTokens,
|
|
13568
13795
|
cachedInputTokens: op.cachedInputTokens,
|
|
@@ -13573,21 +13800,49 @@ var StreamProgress = class {
|
|
|
13573
13800
|
isStreaming: !op.completed,
|
|
13574
13801
|
spinner
|
|
13575
13802
|
});
|
|
13576
|
-
lines.push(`${indent}${
|
|
13803
|
+
lines.push(`${indent}${line2}`);
|
|
13577
13804
|
} else {
|
|
13578
|
-
const
|
|
13579
|
-
|
|
13580
|
-
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
13805
|
+
const termWidth2 = process.stdout.columns ?? 80;
|
|
13806
|
+
const line2 = formatGadgetLine(
|
|
13807
|
+
{
|
|
13808
|
+
name: op.name ?? "",
|
|
13809
|
+
parameters: op.parameters,
|
|
13810
|
+
elapsedSeconds: elapsedSeconds2,
|
|
13811
|
+
isComplete: op.completed ?? false
|
|
13812
|
+
},
|
|
13813
|
+
termWidth2 - indent.length
|
|
13814
|
+
);
|
|
13815
|
+
const indentedLine = line2.split("\n").map((l) => indent + l).join("\n");
|
|
13816
|
+
lines.push(indentedLine);
|
|
13817
|
+
}
|
|
13818
|
+
}
|
|
13819
|
+
}
|
|
13820
|
+
}
|
|
13821
|
+
for (const stream2 of activeNestedStreams) {
|
|
13822
|
+
const indent = " ".repeat(stream2.depth + 2);
|
|
13823
|
+
const elapsedSeconds = (Date.now() - stream2.startTime) / 1e3;
|
|
13824
|
+
const line = formatLLMCallLine({
|
|
13825
|
+
iteration: stream2.iteration,
|
|
13826
|
+
parentCallNumber: stream2.parentCallNumber,
|
|
13827
|
+
model: stream2.model,
|
|
13828
|
+
inputTokens: stream2.inputTokens,
|
|
13829
|
+
cachedInputTokens: stream2.cachedInputTokens,
|
|
13830
|
+
outputTokens: stream2.outputTokens,
|
|
13831
|
+
elapsedSeconds,
|
|
13832
|
+
cost: stream2.cost,
|
|
13833
|
+
isStreaming: true,
|
|
13834
|
+
spinner
|
|
13835
|
+
});
|
|
13836
|
+
lines.push(`${indent}${line}`);
|
|
13588
13837
|
}
|
|
13589
|
-
this.
|
|
13590
|
-
|
|
13838
|
+
if (this.mode === "streaming") {
|
|
13839
|
+
lines.push(this.formatStreamingLine(spinner));
|
|
13840
|
+
} else {
|
|
13841
|
+
lines.push(this.formatCumulativeLine(spinner));
|
|
13842
|
+
}
|
|
13843
|
+
const output = lines.join("\n");
|
|
13844
|
+
this.lastRenderLineCount = (output.match(/\n/g) || []).length + 1;
|
|
13845
|
+
this.target.write("\r" + output);
|
|
13591
13846
|
this.hasRendered = true;
|
|
13592
13847
|
}
|
|
13593
13848
|
/**
|
|
@@ -14199,6 +14454,7 @@ async function executeAgent(promptArg, options, env) {
|
|
|
14199
14454
|
env.stderr.write(`${summary}
|
|
14200
14455
|
`);
|
|
14201
14456
|
}
|
|
14457
|
+
env.stderr.write("\n");
|
|
14202
14458
|
}
|
|
14203
14459
|
if (llmSessionDir) {
|
|
14204
14460
|
const filename = `${formatCallNumber(llmCallCounter)}.response`;
|
|
@@ -14305,8 +14561,7 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
14305
14561
|
builder.withTrailingMessage(
|
|
14306
14562
|
(ctx) => [
|
|
14307
14563
|
`[Iteration ${ctx.iteration + 1}/${ctx.maxIterations}]`,
|
|
14308
|
-
"Think carefully: what gadget invocations can
|
|
14309
|
-
"Maximize efficiency by batching independent operations in a single response."
|
|
14564
|
+
"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
14565
|
].join(" ")
|
|
14311
14566
|
);
|
|
14312
14567
|
if (!options.quiet) {
|
|
@@ -14319,8 +14574,14 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
14319
14574
|
subagentEvent.gadgetInvocationId,
|
|
14320
14575
|
subagentEvent.depth,
|
|
14321
14576
|
info.model,
|
|
14322
|
-
info.iteration,
|
|
14323
|
-
|
|
14577
|
+
info.iteration + 1,
|
|
14578
|
+
// Make 1-indexed like main agent
|
|
14579
|
+
{
|
|
14580
|
+
inputTokens: info.usage?.inputTokens ?? info.inputTokens,
|
|
14581
|
+
cachedInputTokens: info.usage?.cachedInputTokens
|
|
14582
|
+
},
|
|
14583
|
+
llmCallCounter
|
|
14584
|
+
// Parent call number for hierarchical display (e.g., #1.2)
|
|
14324
14585
|
);
|
|
14325
14586
|
} else if (subagentEvent.type === "llm_call_end") {
|
|
14326
14587
|
const info = subagentEvent.event;
|
|
@@ -14364,6 +14625,9 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
14364
14625
|
let textBuffer = "";
|
|
14365
14626
|
const flushTextBuffer = () => {
|
|
14366
14627
|
if (textBuffer) {
|
|
14628
|
+
if (!options.quiet) {
|
|
14629
|
+
progress.clearCompletedGadgets();
|
|
14630
|
+
}
|
|
14367
14631
|
const output = options.quiet ? textBuffer : renderMarkdownWithSeparators(textBuffer);
|
|
14368
14632
|
printer.write(output);
|
|
14369
14633
|
textBuffer = "";
|
|
@@ -14386,7 +14650,7 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
14386
14650
|
} else if (event.type === "gadget_result") {
|
|
14387
14651
|
flushTextBuffer();
|
|
14388
14652
|
if (!options.quiet) {
|
|
14389
|
-
progress.
|
|
14653
|
+
progress.completeGadget(event.result.invocationId);
|
|
14390
14654
|
}
|
|
14391
14655
|
progress.pause();
|
|
14392
14656
|
if (options.quiet) {
|
|
@@ -14397,10 +14661,23 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
14397
14661
|
}
|
|
14398
14662
|
} else {
|
|
14399
14663
|
const tokenCount = await countGadgetOutputTokens(event.result.result);
|
|
14400
|
-
|
|
14401
|
-
|
|
14402
|
-
`
|
|
14664
|
+
const subagentMetrics = progress.getAggregatedSubagentMetrics(
|
|
14665
|
+
event.result.invocationId
|
|
14403
14666
|
);
|
|
14667
|
+
const summary = formatGadgetSummary2({
|
|
14668
|
+
...event.result,
|
|
14669
|
+
tokenCount,
|
|
14670
|
+
media: event.result.storedMedia,
|
|
14671
|
+
subagentMetrics: subagentMetrics.callCount > 0 ? subagentMetrics : void 0
|
|
14672
|
+
});
|
|
14673
|
+
if (event.result.gadgetName === "TellUser") {
|
|
14674
|
+
env.stderr.write(`${summary}
|
|
14675
|
+
`);
|
|
14676
|
+
} else {
|
|
14677
|
+
const indentedSummary = summary.split("\n").map((line) => " " + line).join("\n");
|
|
14678
|
+
env.stderr.write(`${indentedSummary}
|
|
14679
|
+
`);
|
|
14680
|
+
}
|
|
14404
14681
|
}
|
|
14405
14682
|
if (progress.hasInFlightGadgets()) {
|
|
14406
14683
|
progress.start();
|