@narumitw/pi-subagents 0.15.1 → 0.17.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/package.json +1 -1
- package/src/execution.ts +54 -27
- package/src/render.ts +461 -337
- package/src/runner.ts +262 -54
package/src/render.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { AgentScope, SubagentThinkingLevel } from "./agents.js";
|
|
|
12
12
|
import type { SubagentParams } from "./params.js";
|
|
13
13
|
import {
|
|
14
14
|
getResultFinalOutput,
|
|
15
|
+
isResultError,
|
|
15
16
|
type SingleResult,
|
|
16
17
|
type SubagentDetails,
|
|
17
18
|
} from "./runner.js";
|
|
@@ -37,6 +38,8 @@ export function formatUsageStats(
|
|
|
37
38
|
},
|
|
38
39
|
model?: string,
|
|
39
40
|
thinkingLevel?: SubagentThinkingLevel,
|
|
41
|
+
actualProvider?: string,
|
|
42
|
+
actualModel?: string,
|
|
40
43
|
): string {
|
|
41
44
|
const parts: string[] = [];
|
|
42
45
|
if (usage.turns) parts.push(`${usage.turns} turn${usage.turns > 1 ? "s" : ""}`);
|
|
@@ -45,14 +48,27 @@ export function formatUsageStats(
|
|
|
45
48
|
if (usage.cacheRead) parts.push(`R${formatTokens(usage.cacheRead)}`);
|
|
46
49
|
if (usage.cacheWrite) parts.push(`W${formatTokens(usage.cacheWrite)}`);
|
|
47
50
|
if (usage.cost) parts.push(`$${usage.cost.toFixed(4)}`);
|
|
48
|
-
if (usage.contextTokens && usage.contextTokens > 0)
|
|
51
|
+
if (usage.contextTokens && usage.contextTokens > 0)
|
|
49
52
|
parts.push(`ctx:${formatTokens(usage.contextTokens)}`);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
const actual =
|
|
54
|
+
actualProvider && actualModel
|
|
55
|
+
? `${actualProvider}/${actualModel}`
|
|
56
|
+
: (actualModel ?? actualProvider);
|
|
57
|
+
if (actual ?? model) parts.push(actual ?? model ?? "");
|
|
58
|
+
if (thinkingLevel) parts.push(`requested-thinking:${thinkingLevel}`);
|
|
53
59
|
return parts.join(" ");
|
|
54
60
|
}
|
|
55
61
|
|
|
62
|
+
function formatResultUsageStats(result: SingleResult): string {
|
|
63
|
+
return formatUsageStats(
|
|
64
|
+
result.usage,
|
|
65
|
+
result.model,
|
|
66
|
+
result.thinkingLevel,
|
|
67
|
+
result.actualProvider,
|
|
68
|
+
result.actualModel,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
56
72
|
function formatToolCall(
|
|
57
73
|
toolName: string,
|
|
58
74
|
args: Record<string, unknown>,
|
|
@@ -102,7 +118,11 @@ function formatToolCall(
|
|
|
102
118
|
case "find": {
|
|
103
119
|
const pattern = (args.pattern || "*") as string;
|
|
104
120
|
const rawPath = (args.path || ".") as string;
|
|
105
|
-
return
|
|
121
|
+
return (
|
|
122
|
+
themeFg("muted", "find ") +
|
|
123
|
+
themeFg("accent", pattern) +
|
|
124
|
+
themeFg("dim", ` in ${shortenPath(rawPath)}`)
|
|
125
|
+
);
|
|
106
126
|
}
|
|
107
127
|
case "grep": {
|
|
108
128
|
const pattern = (args.pattern || "") as string;
|
|
@@ -130,392 +150,496 @@ function getDisplayItems(messages: Message[]): DisplayItem[] {
|
|
|
130
150
|
for (const msg of messages) {
|
|
131
151
|
if (msg.role === "assistant") {
|
|
132
152
|
for (const part of msg.content) {
|
|
133
|
-
if (part.type === "text")
|
|
134
|
-
|
|
153
|
+
if (part.type === "text") {
|
|
154
|
+
const text = part.text.trim();
|
|
155
|
+
if (text) items.push({ type: "text", text });
|
|
156
|
+
} else if (part.type === "toolCall") {
|
|
157
|
+
items.push({ type: "toolCall", name: part.name, args: part.arguments });
|
|
158
|
+
}
|
|
135
159
|
}
|
|
136
160
|
}
|
|
137
161
|
}
|
|
138
162
|
return items;
|
|
139
163
|
}
|
|
164
|
+
function getCollapsedDisplayItems(result: SingleResult): { items: DisplayItem[]; total: number } {
|
|
165
|
+
if (result.recentActivity && result.recentActivity.length > 0) {
|
|
166
|
+
return {
|
|
167
|
+
items: result.recentActivity,
|
|
168
|
+
total: Math.max(result.recentActivity.length, result.recentActivityTotal ?? 0),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const items = getDisplayItems(result.messages);
|
|
172
|
+
return { items, total: items.length };
|
|
173
|
+
}
|
|
140
174
|
|
|
141
175
|
export function renderSubagentCall(args: SubagentParams, theme: Theme) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
176
|
+
const scope: AgentScope = args.agentScope ?? "user";
|
|
177
|
+
if (args.chain && args.chain.length > 0) {
|
|
178
|
+
let text =
|
|
179
|
+
theme.fg("toolTitle", theme.bold("subagent ")) +
|
|
180
|
+
theme.fg("accent", `chain (${args.chain.length} steps)`) +
|
|
181
|
+
theme.fg("muted", ` [${scope}]`);
|
|
182
|
+
for (let i = 0; i < Math.min(args.chain.length, 3); i++) {
|
|
183
|
+
const step = args.chain[i];
|
|
184
|
+
// Clean up {previous} placeholder for display
|
|
185
|
+
const cleanTask = step.task.replace(/\{previous\}/g, "").trim();
|
|
186
|
+
const preview = cleanTask.length > 40 ? `${cleanTask.slice(0, 40)}...` : cleanTask;
|
|
187
|
+
text +=
|
|
188
|
+
"\n " +
|
|
189
|
+
theme.fg("muted", `${i + 1}.`) +
|
|
190
|
+
" " +
|
|
191
|
+
theme.fg("accent", step.agent) +
|
|
192
|
+
theme.fg("dim", ` ${preview}`);
|
|
193
|
+
}
|
|
194
|
+
if (args.chain.length > 3)
|
|
195
|
+
text += `\n ${theme.fg("muted", `... +${args.chain.length - 3} more`)}`;
|
|
196
|
+
return new Text(text, 0, 0);
|
|
197
|
+
}
|
|
198
|
+
if (args.tasks && args.tasks.length > 0) {
|
|
199
|
+
let text =
|
|
200
|
+
theme.fg("toolTitle", theme.bold("subagent ")) +
|
|
201
|
+
theme.fg("accent", `parallel (${args.tasks.length} tasks)`) +
|
|
202
|
+
theme.fg("muted", ` [${scope}]`);
|
|
203
|
+
for (const t of args.tasks.slice(0, 3)) {
|
|
204
|
+
const preview = t.task.length > 40 ? `${t.task.slice(0, 40)}...` : t.task;
|
|
205
|
+
text += `\n ${theme.fg("accent", t.agent)}${theme.fg("dim", ` ${preview}`)}`;
|
|
206
|
+
}
|
|
207
|
+
if (args.tasks.length > 3)
|
|
208
|
+
text += `\n ${theme.fg("muted", `... +${args.tasks.length - 3} more`)}`;
|
|
209
|
+
if (args.aggregator) {
|
|
210
|
+
const preview =
|
|
211
|
+
args.aggregator.task.length > 40
|
|
212
|
+
? `${args.aggregator.task.slice(0, 40)}...`
|
|
213
|
+
: args.aggregator.task;
|
|
214
|
+
text += `\n ${theme.fg("muted", "fan-in → ")}${theme.fg("accent", args.aggregator.agent)}${theme.fg(
|
|
215
|
+
"dim",
|
|
216
|
+
` ${preview}`,
|
|
217
|
+
)}`;
|
|
218
|
+
}
|
|
219
|
+
return new Text(text, 0, 0);
|
|
220
|
+
}
|
|
221
|
+
const agentName = args.agent || "...";
|
|
222
|
+
const preview = args.task
|
|
223
|
+
? args.task.length > 60
|
|
224
|
+
? `${args.task.slice(0, 60)}...`
|
|
225
|
+
: args.task
|
|
226
|
+
: "...";
|
|
227
|
+
let text =
|
|
228
|
+
theme.fg("toolTitle", theme.bold("subagent ")) +
|
|
229
|
+
theme.fg("accent", agentName) +
|
|
230
|
+
theme.fg("muted", ` [${scope}]`);
|
|
231
|
+
text += `\n ${theme.fg("dim", preview)}`;
|
|
232
|
+
return new Text(text, 0, 0);
|
|
191
233
|
}
|
|
192
234
|
|
|
193
235
|
export function renderSubagentResult(
|
|
194
236
|
result: AgentToolResult<SubagentDetails>,
|
|
195
|
-
{ expanded }: ToolRenderResultOptions,
|
|
237
|
+
{ expanded, isPartial }: ToolRenderResultOptions,
|
|
196
238
|
theme: Theme,
|
|
197
239
|
) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
240
|
+
const details = result.details as SubagentDetails | undefined;
|
|
241
|
+
if (!details || details.results.length === 0) {
|
|
242
|
+
const text = result.content[0];
|
|
243
|
+
return new Text(text?.type === "text" ? text.text : "(no output)", 0, 0);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const mdTheme = getMarkdownTheme();
|
|
247
|
+
|
|
248
|
+
const renderDisplayItems = (items: DisplayItem[], limit?: number, total = items.length) => {
|
|
249
|
+
const toShow = limit ? items.slice(-limit) : items;
|
|
250
|
+
const skipped = Math.max(0, total - toShow.length);
|
|
251
|
+
let text = "";
|
|
252
|
+
if (skipped > 0) text += theme.fg("muted", `... ${skipped} earlier items\n`);
|
|
253
|
+
for (const item of toShow) {
|
|
254
|
+
if (item.type === "text") {
|
|
255
|
+
const preview = expanded ? item.text : item.text.split("\n").slice(0, 3).join("\n");
|
|
256
|
+
text += `${theme.fg("toolOutput", preview)}\n`;
|
|
257
|
+
} else {
|
|
258
|
+
text += `${theme.fg("muted", "→ ") + formatToolCall(item.name, item.args, theme.fg.bind(theme))}\n`;
|
|
202
259
|
}
|
|
260
|
+
}
|
|
261
|
+
return text.trimEnd();
|
|
262
|
+
};
|
|
203
263
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
264
|
+
if (details.mode === "single" && details.results.length === 1) {
|
|
265
|
+
const r = details.results[0];
|
|
266
|
+
const isError = isResultError(r);
|
|
267
|
+
const icon = isError
|
|
268
|
+
? theme.fg("error", "✗")
|
|
269
|
+
: isPartial
|
|
270
|
+
? theme.fg("warning", "⏳")
|
|
271
|
+
: theme.fg("success", "✓");
|
|
272
|
+
const displayItems = getDisplayItems(r.messages);
|
|
273
|
+
const finalOutput = getResultFinalOutput(r);
|
|
274
|
+
|
|
275
|
+
if (expanded) {
|
|
276
|
+
const container = new Container();
|
|
277
|
+
let header = `${icon} ${theme.fg("toolTitle", theme.bold(r.agent))}${theme.fg("muted", ` (${r.agentSource})`)}`;
|
|
278
|
+
if (isError && r.stopReason) header += ` ${theme.fg("error", `[${r.stopReason}]`)}`;
|
|
279
|
+
container.addChild(new Text(header, 0, 0));
|
|
280
|
+
if (isError && r.errorMessage)
|
|
281
|
+
container.addChild(new Text(theme.fg("error", `Error: ${r.errorMessage}`), 0, 0));
|
|
282
|
+
container.addChild(new Spacer(1));
|
|
283
|
+
container.addChild(new Text(theme.fg("muted", "─── Task ───"), 0, 0));
|
|
284
|
+
container.addChild(new Text(theme.fg("dim", r.task), 0, 0));
|
|
285
|
+
container.addChild(new Spacer(1));
|
|
286
|
+
container.addChild(new Text(theme.fg("muted", "─── Output ───"), 0, 0));
|
|
287
|
+
if (displayItems.length === 0 && !finalOutput) {
|
|
288
|
+
container.addChild(new Text(theme.fg("muted", "(no output)"), 0, 0));
|
|
289
|
+
} else {
|
|
290
|
+
for (const item of displayItems) {
|
|
291
|
+
if (item.type === "toolCall")
|
|
292
|
+
container.addChild(
|
|
293
|
+
new Text(
|
|
294
|
+
theme.fg("muted", "→ ") +
|
|
295
|
+
formatToolCall(item.name, item.args, theme.fg.bind(theme)),
|
|
296
|
+
0,
|
|
297
|
+
0,
|
|
298
|
+
),
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
if (finalOutput) {
|
|
302
|
+
container.addChild(new Spacer(1));
|
|
303
|
+
container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
|
|
218
304
|
}
|
|
219
|
-
|
|
220
|
-
|
|
305
|
+
}
|
|
306
|
+
const usageStr = formatResultUsageStats(r);
|
|
307
|
+
if (usageStr) {
|
|
308
|
+
container.addChild(new Spacer(1));
|
|
309
|
+
container.addChild(new Text(theme.fg("dim", usageStr), 0, 0));
|
|
310
|
+
}
|
|
311
|
+
return container;
|
|
312
|
+
}
|
|
221
313
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
314
|
+
const collapsed = getCollapsedDisplayItems(r);
|
|
315
|
+
let text = `${icon} ${theme.fg("toolTitle", theme.bold(r.agent))}${theme.fg("muted", ` (${r.agentSource})`)}`;
|
|
316
|
+
if (isError && r.stopReason) text += ` ${theme.fg("error", `[${r.stopReason}]`)}`;
|
|
317
|
+
if (isError && r.errorMessage) text += `\n${theme.fg("error", `Error: ${r.errorMessage}`)}`;
|
|
318
|
+
if (collapsed.items.length > 0) {
|
|
319
|
+
text += `\n${renderDisplayItems(collapsed.items, COLLAPSED_ITEM_COUNT, collapsed.total)}`;
|
|
320
|
+
if (collapsed.total > COLLAPSED_ITEM_COUNT)
|
|
321
|
+
text += `\n${theme.fg("muted", "(Ctrl+O to expand)")}`;
|
|
322
|
+
} else if (finalOutput.trim()) {
|
|
323
|
+
text += `\n${theme.fg("toolOutput", finalOutput.trim().split("\n").slice(0, 3).join("\n"))}`;
|
|
324
|
+
} else if (!isError || !r.errorMessage) {
|
|
325
|
+
text += `\n${theme.fg("muted", isPartial && !isError ? "(running...)" : "(no output)")}`;
|
|
326
|
+
}
|
|
327
|
+
const usageStr = formatResultUsageStats(r);
|
|
328
|
+
if (usageStr) text += `\n${theme.fg("dim", usageStr)}`;
|
|
329
|
+
return new Text(text, 0, 0);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const aggregateUsage = (results: SingleResult[]) => {
|
|
333
|
+
const total = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
|
|
334
|
+
for (const r of results) {
|
|
335
|
+
total.input += r.usage.input;
|
|
336
|
+
total.output += r.usage.output;
|
|
337
|
+
total.cacheRead += r.usage.cacheRead;
|
|
338
|
+
total.cacheWrite += r.usage.cacheWrite;
|
|
339
|
+
total.cost += r.usage.cost;
|
|
340
|
+
total.turns += r.usage.turns;
|
|
341
|
+
}
|
|
342
|
+
return total;
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
if (details.mode === "chain") {
|
|
346
|
+
const currentResult = details.results.at(-1);
|
|
347
|
+
const currentIsRunning =
|
|
348
|
+
isPartial && currentResult !== undefined && !isResultError(currentResult);
|
|
349
|
+
const successCount = details.results.filter(
|
|
350
|
+
(result) => !isResultError(result) && (!currentIsRunning || result !== currentResult),
|
|
351
|
+
).length;
|
|
352
|
+
const icon = currentIsRunning
|
|
353
|
+
? theme.fg("warning", "⏳")
|
|
354
|
+
: successCount === details.results.length
|
|
355
|
+
? theme.fg("success", "✓")
|
|
356
|
+
: theme.fg("error", "✗");
|
|
357
|
+
|
|
358
|
+
if (expanded) {
|
|
359
|
+
const container = new Container();
|
|
360
|
+
container.addChild(
|
|
361
|
+
new Text(
|
|
362
|
+
icon +
|
|
363
|
+
" " +
|
|
364
|
+
theme.fg("toolTitle", theme.bold("chain ")) +
|
|
365
|
+
theme.fg("accent", `${successCount}/${details.results.length} steps`),
|
|
366
|
+
0,
|
|
367
|
+
0,
|
|
368
|
+
),
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
for (const r of details.results) {
|
|
372
|
+
const rFailed = isResultError(r);
|
|
373
|
+
const rIcon = rFailed
|
|
374
|
+
? theme.fg("error", "✗")
|
|
375
|
+
: currentIsRunning && r === currentResult
|
|
376
|
+
? theme.fg("warning", "⏳")
|
|
377
|
+
: theme.fg("success", "✓");
|
|
226
378
|
const displayItems = getDisplayItems(r.messages);
|
|
227
379
|
const finalOutput = getResultFinalOutput(r);
|
|
228
380
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
container.addChild(new
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
if (finalOutput) {
|
|
255
|
-
container.addChild(new Spacer(1));
|
|
256
|
-
container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
const usageStr = formatUsageStats(r.usage, r.model, r.thinkingLevel);
|
|
260
|
-
if (usageStr) {
|
|
261
|
-
container.addChild(new Spacer(1));
|
|
262
|
-
container.addChild(new Text(theme.fg("dim", usageStr), 0, 0));
|
|
381
|
+
container.addChild(new Spacer(1));
|
|
382
|
+
container.addChild(
|
|
383
|
+
new Text(
|
|
384
|
+
`${theme.fg("muted", `─── Step ${r.step}: `) + theme.fg("accent", r.agent)} ${rIcon}`,
|
|
385
|
+
0,
|
|
386
|
+
0,
|
|
387
|
+
),
|
|
388
|
+
);
|
|
389
|
+
container.addChild(new Text(theme.fg("muted", "Task: ") + theme.fg("dim", r.task), 0, 0));
|
|
390
|
+
if (rFailed && r.errorMessage)
|
|
391
|
+
container.addChild(new Text(theme.fg("error", `Error: ${r.errorMessage}`), 0, 0));
|
|
392
|
+
|
|
393
|
+
// Show tool calls
|
|
394
|
+
for (const item of displayItems) {
|
|
395
|
+
if (item.type === "toolCall") {
|
|
396
|
+
container.addChild(
|
|
397
|
+
new Text(
|
|
398
|
+
theme.fg("muted", "→ ") +
|
|
399
|
+
formatToolCall(item.name, item.args, theme.fg.bind(theme)),
|
|
400
|
+
0,
|
|
401
|
+
0,
|
|
402
|
+
),
|
|
403
|
+
);
|
|
263
404
|
}
|
|
264
|
-
return container;
|
|
265
405
|
}
|
|
266
406
|
|
|
267
|
-
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
else {
|
|
272
|
-
text += `\n${renderDisplayItems(displayItems, COLLAPSED_ITEM_COUNT)}`;
|
|
273
|
-
if (displayItems.length > COLLAPSED_ITEM_COUNT) text += `\n${theme.fg("muted", "(Ctrl+O to expand)")}`;
|
|
407
|
+
// Show final output as markdown
|
|
408
|
+
if (finalOutput) {
|
|
409
|
+
container.addChild(new Spacer(1));
|
|
410
|
+
container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
|
|
274
411
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
412
|
+
|
|
413
|
+
const stepUsage = formatResultUsageStats(r);
|
|
414
|
+
if (stepUsage) container.addChild(new Text(theme.fg("dim", stepUsage), 0, 0));
|
|
278
415
|
}
|
|
279
416
|
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
total.cost += r.usage.cost;
|
|
288
|
-
total.turns += r.usage.turns;
|
|
289
|
-
}
|
|
290
|
-
return total;
|
|
291
|
-
};
|
|
417
|
+
const usageStr = formatUsageStats(aggregateUsage(details.results));
|
|
418
|
+
if (usageStr) {
|
|
419
|
+
container.addChild(new Spacer(1));
|
|
420
|
+
container.addChild(new Text(theme.fg("dim", `Total: ${usageStr}`), 0, 0));
|
|
421
|
+
}
|
|
422
|
+
return container;
|
|
423
|
+
}
|
|
292
424
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
425
|
+
// Collapsed view
|
|
426
|
+
let text =
|
|
427
|
+
icon +
|
|
428
|
+
" " +
|
|
429
|
+
theme.fg("toolTitle", theme.bold("chain ")) +
|
|
430
|
+
theme.fg("accent", `${successCount}/${details.results.length} steps`);
|
|
431
|
+
for (const r of details.results) {
|
|
432
|
+
const rFailed = isResultError(r);
|
|
433
|
+
const rIcon = rFailed
|
|
434
|
+
? theme.fg("error", "✗")
|
|
435
|
+
: currentIsRunning && r === currentResult
|
|
436
|
+
? theme.fg("warning", "⏳")
|
|
437
|
+
: theme.fg("success", "✓");
|
|
438
|
+
const collapsed = getCollapsedDisplayItems(r);
|
|
439
|
+
const finalOutput = getResultFinalOutput(r).trim();
|
|
440
|
+
text += `\n\n${theme.fg("muted", `─── Step ${r.step}: `)}${theme.fg("accent", r.agent)} ${rIcon}`;
|
|
441
|
+
if (rFailed && r.errorMessage)
|
|
442
|
+
text += `\n${theme.fg("error", `Error: ${r.errorMessage}`)}`;
|
|
443
|
+
if (collapsed.items.length > 0)
|
|
444
|
+
text += `\n${renderDisplayItems(collapsed.items, 5, collapsed.total)}`;
|
|
445
|
+
else if (currentIsRunning && r === currentResult)
|
|
446
|
+
text += `\n${theme.fg("muted", "(running...)")}`;
|
|
447
|
+
else if (finalOutput)
|
|
448
|
+
text += `\n${theme.fg("toolOutput", finalOutput.split("\n").slice(0, 3).join("\n"))}`;
|
|
449
|
+
else if (!rFailed || !r.errorMessage) text += `\n${theme.fg("muted", "(no output)")}`;
|
|
450
|
+
}
|
|
451
|
+
const usageStr = formatUsageStats(aggregateUsage(details.results));
|
|
452
|
+
if (usageStr) text += `\n\n${theme.fg("dim", `Total: ${usageStr}`)}`;
|
|
453
|
+
text += `\n${theme.fg("muted", "(Ctrl+O to expand)")}`;
|
|
454
|
+
return new Text(text, 0, 0);
|
|
455
|
+
}
|
|
296
456
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
457
|
+
if (details.mode === "parallel") {
|
|
458
|
+
const resultIsRunning = (result: SingleResult) =>
|
|
459
|
+
result.exitCode === -1 && !isResultError(result);
|
|
460
|
+
const running = details.results.filter(resultIsRunning).length;
|
|
461
|
+
const successCount = details.results.filter(
|
|
462
|
+
(result) => result.exitCode !== -1 && !isResultError(result),
|
|
463
|
+
).length;
|
|
464
|
+
const failCount = details.results.filter(isResultError).length;
|
|
465
|
+
const aggregator = details.aggregator;
|
|
466
|
+
const aggregatorFailed = aggregator ? isResultError(aggregator) : false;
|
|
467
|
+
const aggregatorRunning = aggregator
|
|
468
|
+
? !aggregatorFailed && (isPartial || aggregator.exitCode === -1)
|
|
469
|
+
: false;
|
|
470
|
+
const pendingSuccessfulSettlement =
|
|
471
|
+
isPartial && !aggregator && running === 0 && failCount === 0;
|
|
472
|
+
const isRunning = running > 0 || aggregatorRunning || pendingSuccessfulSettlement;
|
|
473
|
+
const icon = isRunning
|
|
474
|
+
? theme.fg("warning", "⏳")
|
|
475
|
+
: failCount > 0 || aggregatorFailed
|
|
476
|
+
? theme.fg("warning", "◐")
|
|
477
|
+
: theme.fg("success", "✓");
|
|
478
|
+
const status = isRunning
|
|
479
|
+
? aggregatorRunning
|
|
480
|
+
? `${successCount + failCount}/${details.results.length} done, fan-in running`
|
|
481
|
+
: running > 0
|
|
482
|
+
? `${successCount + failCount}/${details.results.length} done, ${running} running`
|
|
483
|
+
: `${successCount + failCount}/${details.results.length} done, running`
|
|
484
|
+
: aggregator
|
|
485
|
+
? `${successCount}/${details.results.length} tasks + fan-in`
|
|
486
|
+
: `${successCount}/${details.results.length} tasks`;
|
|
487
|
+
|
|
488
|
+
if (expanded && !isRunning) {
|
|
489
|
+
const container = new Container();
|
|
490
|
+
container.addChild(
|
|
491
|
+
new Text(
|
|
492
|
+
`${icon} ${theme.fg("toolTitle", theme.bold("parallel "))}${theme.fg("accent", status)}`,
|
|
493
|
+
0,
|
|
494
|
+
0,
|
|
495
|
+
),
|
|
496
|
+
);
|
|
309
497
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
498
|
+
for (const r of details.results) {
|
|
499
|
+
const rFailed = isResultError(r);
|
|
500
|
+
const rIcon = rFailed
|
|
501
|
+
? theme.fg("error", "✗")
|
|
502
|
+
: resultIsRunning(r)
|
|
503
|
+
? theme.fg("warning", "⏳")
|
|
504
|
+
: theme.fg("success", "✓");
|
|
505
|
+
const displayItems = getDisplayItems(r.messages);
|
|
506
|
+
const finalOutput = getResultFinalOutput(r);
|
|
314
507
|
|
|
315
|
-
|
|
508
|
+
container.addChild(new Spacer(1));
|
|
509
|
+
container.addChild(
|
|
510
|
+
new Text(`${theme.fg("muted", "─── ") + theme.fg("accent", r.agent)} ${rIcon}`, 0, 0),
|
|
511
|
+
);
|
|
512
|
+
container.addChild(new Text(theme.fg("muted", "Task: ") + theme.fg("dim", r.task), 0, 0));
|
|
513
|
+
if (rFailed && r.errorMessage)
|
|
514
|
+
container.addChild(new Text(theme.fg("error", `Error: ${r.errorMessage}`), 0, 0));
|
|
515
|
+
|
|
516
|
+
// Show tool calls
|
|
517
|
+
for (const item of displayItems) {
|
|
518
|
+
if (item.type === "toolCall") {
|
|
316
519
|
container.addChild(
|
|
317
520
|
new Text(
|
|
318
|
-
|
|
521
|
+
theme.fg("muted", "→ ") +
|
|
522
|
+
formatToolCall(item.name, item.args, theme.fg.bind(theme)),
|
|
319
523
|
0,
|
|
320
524
|
0,
|
|
321
525
|
),
|
|
322
526
|
);
|
|
323
|
-
container.addChild(new Text(theme.fg("muted", "Task: ") + theme.fg("dim", r.task), 0, 0));
|
|
324
|
-
|
|
325
|
-
// Show tool calls
|
|
326
|
-
for (const item of displayItems) {
|
|
327
|
-
if (item.type === "toolCall") {
|
|
328
|
-
container.addChild(
|
|
329
|
-
new Text(
|
|
330
|
-
theme.fg("muted", "→ ") + formatToolCall(item.name, item.args, theme.fg.bind(theme)),
|
|
331
|
-
0,
|
|
332
|
-
0,
|
|
333
|
-
),
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Show final output as markdown
|
|
339
|
-
if (finalOutput) {
|
|
340
|
-
container.addChild(new Spacer(1));
|
|
341
|
-
container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const stepUsage = formatUsageStats(r.usage, r.model, r.thinkingLevel);
|
|
345
|
-
if (stepUsage) container.addChild(new Text(theme.fg("dim", stepUsage), 0, 0));
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const usageStr = formatUsageStats(aggregateUsage(details.results));
|
|
349
|
-
if (usageStr) {
|
|
350
|
-
container.addChild(new Spacer(1));
|
|
351
|
-
container.addChild(new Text(theme.fg("dim", `Total: ${usageStr}`), 0, 0));
|
|
352
527
|
}
|
|
353
|
-
return container;
|
|
354
528
|
}
|
|
355
529
|
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
theme.fg("toolTitle", theme.bold("chain ")) +
|
|
361
|
-
theme.fg("accent", `${successCount}/${details.results.length} steps`);
|
|
362
|
-
for (const r of details.results) {
|
|
363
|
-
const rIcon = r.exitCode === 0 ? theme.fg("success", "✓") : theme.fg("error", "✗");
|
|
364
|
-
const displayItems = getDisplayItems(r.messages);
|
|
365
|
-
text += `\n\n${theme.fg("muted", `─── Step ${r.step}: `)}${theme.fg("accent", r.agent)} ${rIcon}`;
|
|
366
|
-
if (displayItems.length === 0) text += `\n${theme.fg("muted", "(no output)")}`;
|
|
367
|
-
else text += `\n${renderDisplayItems(displayItems, 5)}`;
|
|
530
|
+
// Show final output as markdown
|
|
531
|
+
if (finalOutput) {
|
|
532
|
+
container.addChild(new Spacer(1));
|
|
533
|
+
container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
|
|
368
534
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
return new Text(text, 0, 0);
|
|
535
|
+
|
|
536
|
+
const taskUsage = formatResultUsageStats(r);
|
|
537
|
+
if (taskUsage) container.addChild(new Text(theme.fg("dim", taskUsage), 0, 0));
|
|
373
538
|
}
|
|
374
539
|
|
|
375
|
-
if (
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const aggregatorRunning = aggregator?.exitCode === -1;
|
|
381
|
-
const aggregatorFailed = aggregator ? aggregator.exitCode > 0 || aggregator.stopReason === "error" : false;
|
|
382
|
-
const isRunning = running > 0 || aggregatorRunning;
|
|
383
|
-
const icon = isRunning
|
|
384
|
-
? theme.fg("warning", "⏳")
|
|
385
|
-
: failCount > 0 || aggregatorFailed
|
|
386
|
-
? theme.fg("warning", "◐")
|
|
540
|
+
if (aggregator) {
|
|
541
|
+
const rIcon = aggregatorFailed
|
|
542
|
+
? theme.fg("error", "✗")
|
|
543
|
+
: aggregatorRunning
|
|
544
|
+
? theme.fg("warning", "⏳")
|
|
387
545
|
: theme.fg("success", "✓");
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
546
|
+
const displayItems = getDisplayItems(aggregator.messages);
|
|
547
|
+
const finalOutput = getResultFinalOutput(aggregator);
|
|
548
|
+
|
|
549
|
+
container.addChild(new Spacer(1));
|
|
550
|
+
container.addChild(
|
|
551
|
+
new Text(
|
|
552
|
+
`${theme.fg("muted", "─── fan-in → ") + theme.fg("accent", aggregator.agent)} ${rIcon}`,
|
|
553
|
+
0,
|
|
554
|
+
0,
|
|
555
|
+
),
|
|
556
|
+
);
|
|
557
|
+
container.addChild(
|
|
558
|
+
new Text(theme.fg("muted", "Task: ") + theme.fg("dim", aggregator.task), 0, 0),
|
|
559
|
+
);
|
|
560
|
+
if (aggregatorFailed && aggregator.errorMessage)
|
|
398
561
|
container.addChild(
|
|
399
|
-
new Text(
|
|
400
|
-
`${icon} ${theme.fg("toolTitle", theme.bold("parallel "))}${theme.fg("accent", status)}`,
|
|
401
|
-
0,
|
|
402
|
-
0,
|
|
403
|
-
),
|
|
562
|
+
new Text(theme.fg("error", `Error: ${aggregator.errorMessage}`), 0, 0),
|
|
404
563
|
);
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const rIcon = r.exitCode === 0 ? theme.fg("success", "✓") : theme.fg("error", "✗");
|
|
408
|
-
const displayItems = getDisplayItems(r.messages);
|
|
409
|
-
const finalOutput = getResultFinalOutput(r);
|
|
410
|
-
|
|
411
|
-
container.addChild(new Spacer(1));
|
|
412
|
-
container.addChild(
|
|
413
|
-
new Text(`${theme.fg("muted", "─── ") + theme.fg("accent", r.agent)} ${rIcon}`, 0, 0),
|
|
414
|
-
);
|
|
415
|
-
container.addChild(new Text(theme.fg("muted", "Task: ") + theme.fg("dim", r.task), 0, 0));
|
|
416
|
-
|
|
417
|
-
// Show tool calls
|
|
418
|
-
for (const item of displayItems) {
|
|
419
|
-
if (item.type === "toolCall") {
|
|
420
|
-
container.addChild(
|
|
421
|
-
new Text(
|
|
422
|
-
theme.fg("muted", "→ ") + formatToolCall(item.name, item.args, theme.fg.bind(theme)),
|
|
423
|
-
0,
|
|
424
|
-
0,
|
|
425
|
-
),
|
|
426
|
-
);
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// Show final output as markdown
|
|
431
|
-
if (finalOutput) {
|
|
432
|
-
container.addChild(new Spacer(1));
|
|
433
|
-
container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
const taskUsage = formatUsageStats(r.usage, r.model, r.thinkingLevel);
|
|
437
|
-
if (taskUsage) container.addChild(new Text(theme.fg("dim", taskUsage), 0, 0));
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
if (aggregator) {
|
|
441
|
-
const rIcon = aggregator.exitCode === 0 ? theme.fg("success", "✓") : theme.fg("error", "✗");
|
|
442
|
-
const displayItems = getDisplayItems(aggregator.messages);
|
|
443
|
-
const finalOutput = getResultFinalOutput(aggregator);
|
|
444
|
-
|
|
445
|
-
container.addChild(new Spacer(1));
|
|
564
|
+
for (const item of displayItems) {
|
|
565
|
+
if (item.type === "toolCall") {
|
|
446
566
|
container.addChild(
|
|
447
567
|
new Text(
|
|
448
|
-
|
|
568
|
+
theme.fg("muted", "→ ") +
|
|
569
|
+
formatToolCall(item.name, item.args, theme.fg.bind(theme)),
|
|
449
570
|
0,
|
|
450
571
|
0,
|
|
451
572
|
),
|
|
452
573
|
);
|
|
453
|
-
container.addChild(new Text(theme.fg("muted", "Task: ") + theme.fg("dim", aggregator.task), 0, 0));
|
|
454
|
-
for (const item of displayItems) {
|
|
455
|
-
if (item.type === "toolCall") {
|
|
456
|
-
container.addChild(
|
|
457
|
-
new Text(
|
|
458
|
-
theme.fg("muted", "→ ") + formatToolCall(item.name, item.args, theme.fg.bind(theme)),
|
|
459
|
-
0,
|
|
460
|
-
0,
|
|
461
|
-
),
|
|
462
|
-
);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
if (finalOutput) {
|
|
466
|
-
container.addChild(new Spacer(1));
|
|
467
|
-
container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
|
|
468
|
-
}
|
|
469
|
-
const fanInUsage = formatUsageStats(aggregator.usage, aggregator.model, aggregator.thinkingLevel);
|
|
470
|
-
if (fanInUsage) container.addChild(new Text(theme.fg("dim", fanInUsage), 0, 0));
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const usageResults = aggregator ? [...details.results, aggregator] : details.results;
|
|
474
|
-
const usageStr = formatUsageStats(aggregateUsage(usageResults));
|
|
475
|
-
if (usageStr) {
|
|
476
|
-
container.addChild(new Spacer(1));
|
|
477
|
-
container.addChild(new Text(theme.fg("dim", `Total: ${usageStr}`), 0, 0));
|
|
478
574
|
}
|
|
479
|
-
return container;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// Collapsed view (or still running)
|
|
483
|
-
let text = `${icon} ${theme.fg("toolTitle", theme.bold("parallel "))}${theme.fg("accent", status)}`;
|
|
484
|
-
for (const r of details.results) {
|
|
485
|
-
const rIcon =
|
|
486
|
-
r.exitCode === -1
|
|
487
|
-
? theme.fg("warning", "⏳")
|
|
488
|
-
: r.exitCode === 0
|
|
489
|
-
? theme.fg("success", "✓")
|
|
490
|
-
: theme.fg("error", "✗");
|
|
491
|
-
const displayItems = getDisplayItems(r.messages);
|
|
492
|
-
text += `\n\n${theme.fg("muted", "─── ")}${theme.fg("accent", r.agent)} ${rIcon}`;
|
|
493
|
-
if (displayItems.length === 0)
|
|
494
|
-
text += `\n${theme.fg("muted", r.exitCode === -1 ? "(running...)" : "(no output)")}`;
|
|
495
|
-
else text += `\n${renderDisplayItems(displayItems, 5)}`;
|
|
496
575
|
}
|
|
497
|
-
if (
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
? theme.fg("warning", "⏳")
|
|
501
|
-
: aggregator.exitCode === 0
|
|
502
|
-
? theme.fg("success", "✓")
|
|
503
|
-
: theme.fg("error", "✗");
|
|
504
|
-
const displayItems = getDisplayItems(aggregator.messages);
|
|
505
|
-
text += `\n\n${theme.fg("muted", "─── fan-in → ")}${theme.fg("accent", aggregator.agent)} ${rIcon}`;
|
|
506
|
-
if (displayItems.length === 0)
|
|
507
|
-
text += `\n${theme.fg("muted", aggregator.exitCode === -1 ? "(running...)" : "(no output)")}`;
|
|
508
|
-
else text += `\n${renderDisplayItems(displayItems, 5)}`;
|
|
509
|
-
}
|
|
510
|
-
if (!isRunning) {
|
|
511
|
-
const usageResults = aggregator ? [...details.results, aggregator] : details.results;
|
|
512
|
-
const usageStr = formatUsageStats(aggregateUsage(usageResults));
|
|
513
|
-
if (usageStr) text += `\n\n${theme.fg("dim", `Total: ${usageStr}`)}`;
|
|
576
|
+
if (finalOutput) {
|
|
577
|
+
container.addChild(new Spacer(1));
|
|
578
|
+
container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
|
|
514
579
|
}
|
|
515
|
-
|
|
516
|
-
|
|
580
|
+
const fanInUsage = formatResultUsageStats(aggregator);
|
|
581
|
+
if (fanInUsage) container.addChild(new Text(theme.fg("dim", fanInUsage), 0, 0));
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const usageResults = aggregator ? [...details.results, aggregator] : details.results;
|
|
585
|
+
const usageStr = formatUsageStats(aggregateUsage(usageResults));
|
|
586
|
+
if (usageStr) {
|
|
587
|
+
container.addChild(new Spacer(1));
|
|
588
|
+
container.addChild(new Text(theme.fg("dim", `Total: ${usageStr}`), 0, 0));
|
|
517
589
|
}
|
|
590
|
+
return container;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Collapsed view (or still running)
|
|
594
|
+
let text = `${icon} ${theme.fg("toolTitle", theme.bold("parallel "))}${theme.fg("accent", status)}`;
|
|
595
|
+
for (const r of details.results) {
|
|
596
|
+
const rFailed = isResultError(r);
|
|
597
|
+
const rRunning = resultIsRunning(r);
|
|
598
|
+
const rIcon = rFailed
|
|
599
|
+
? theme.fg("error", "✗")
|
|
600
|
+
: rRunning
|
|
601
|
+
? theme.fg("warning", "⏳")
|
|
602
|
+
: theme.fg("success", "✓");
|
|
603
|
+
const collapsed = getCollapsedDisplayItems(r);
|
|
604
|
+
const finalOutput = getResultFinalOutput(r).trim();
|
|
605
|
+
text += `\n\n${theme.fg("muted", "─── ")}${theme.fg("accent", r.agent)} ${rIcon}`;
|
|
606
|
+
if (rFailed && r.errorMessage)
|
|
607
|
+
text += `\n${theme.fg("error", `Error: ${r.errorMessage}`)}`;
|
|
608
|
+
if (collapsed.items.length > 0)
|
|
609
|
+
text += `\n${renderDisplayItems(collapsed.items, 5, collapsed.total)}`;
|
|
610
|
+
else if (rRunning) text += `\n${theme.fg("muted", "(running...)")}`;
|
|
611
|
+
else if (finalOutput)
|
|
612
|
+
text += `\n${theme.fg("toolOutput", finalOutput.split("\n").slice(0, 3).join("\n"))}`;
|
|
613
|
+
else if (!rFailed || !r.errorMessage) text += `\n${theme.fg("muted", "(no output)")}`;
|
|
614
|
+
}
|
|
615
|
+
if (aggregator) {
|
|
616
|
+
const rIcon = aggregatorFailed
|
|
617
|
+
? theme.fg("error", "✗")
|
|
618
|
+
: aggregatorRunning
|
|
619
|
+
? theme.fg("warning", "⏳")
|
|
620
|
+
: theme.fg("success", "✓");
|
|
621
|
+
const collapsed = getCollapsedDisplayItems(aggregator);
|
|
622
|
+
const finalOutput = getResultFinalOutput(aggregator).trim();
|
|
623
|
+
text += `\n\n${theme.fg("muted", "─── fan-in → ")}${theme.fg("accent", aggregator.agent)} ${rIcon}`;
|
|
624
|
+
if (aggregatorFailed && aggregator.errorMessage)
|
|
625
|
+
text += `\n${theme.fg("error", `Error: ${aggregator.errorMessage}`)}`;
|
|
626
|
+
if (collapsed.items.length > 0)
|
|
627
|
+
text += `\n${renderDisplayItems(collapsed.items, 5, collapsed.total)}`;
|
|
628
|
+
else if (aggregatorRunning) text += `\n${theme.fg("muted", "(running...)")}`;
|
|
629
|
+
else if (finalOutput)
|
|
630
|
+
text += `\n${theme.fg("toolOutput", finalOutput.split("\n").slice(0, 3).join("\n"))}`;
|
|
631
|
+
else if (!aggregatorFailed || !aggregator.errorMessage)
|
|
632
|
+
text += `\n${theme.fg("muted", "(no output)")}`;
|
|
633
|
+
}
|
|
634
|
+
if (!isRunning) {
|
|
635
|
+
const usageResults = aggregator ? [...details.results, aggregator] : details.results;
|
|
636
|
+
const usageStr = formatUsageStats(aggregateUsage(usageResults));
|
|
637
|
+
if (usageStr) text += `\n\n${theme.fg("dim", `Total: ${usageStr}`)}`;
|
|
638
|
+
}
|
|
639
|
+
if (!expanded) text += `\n${theme.fg("muted", "(Ctrl+O to expand)")}`;
|
|
640
|
+
return new Text(text, 0, 0);
|
|
641
|
+
}
|
|
518
642
|
|
|
519
|
-
|
|
520
|
-
|
|
643
|
+
const text = result.content[0];
|
|
644
|
+
return new Text(text?.type === "text" ? text.text : "(no output)", 0, 0);
|
|
521
645
|
}
|