mixdog 0.9.66 → 0.9.67
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/runtime/agent/orchestrator/session/store-summary-index.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -0
- package/src/runtime/channels/lib/config.mjs +7 -0
- package/src/runtime/channels/lib/status-snapshot.mjs +6 -30
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +203 -0
- package/src/runtime/channels/lib/webhook.mjs +23 -201
- package/src/runtime/shared/config.mjs +0 -9
- package/src/runtime/shared/time-format.mjs +56 -0
- package/src/runtime/shared/tool-card-model.mjs +740 -0
- package/src/session-runtime/channel-config-api.mjs +5 -0
- package/src/session-runtime/lifecycle-api.mjs +5 -0
- package/src/session-runtime/prewarm.mjs +13 -7
- package/src/session-runtime/runtime-core.mjs +28 -9
- package/src/session-runtime/session-text.mjs +6 -0
- package/src/session-runtime/settings-api.mjs +0 -12
- package/src/standalone/channel-admin.mjs +35 -21
- package/src/tui/App.jsx +0 -15
- package/src/tui/app/channel-pickers.mjs +18 -42
- package/src/tui/app/doctor.mjs +0 -1
- package/src/tui/components/ToolExecution.jsx +47 -196
- package/src/tui/components/tool-execution/surface-detail.mjs +33 -394
- package/src/tui/components/tool-execution/text-format.mjs +27 -104
- package/src/tui/dist/index.mjs +306 -185
- package/src/tui/engine/live-share.mjs +9 -0
- package/src/tui/engine/session-api-ext.mjs +0 -10
- package/src/tui/time-format.mjs +4 -51
- package/src/runtime/channels/lib/webhook/ngrok.mjs +0 -181
|
@@ -18,13 +18,9 @@ import { BULLET_OPERATOR } from '../figures.mjs';
|
|
|
18
18
|
import {
|
|
19
19
|
displayToolName as surfaceDisplayToolName,
|
|
20
20
|
formatToolSurface,
|
|
21
|
-
summarizeToolResult as surfaceSummarizeToolResult,
|
|
22
21
|
formatAggregateHeader,
|
|
23
|
-
formatToolActionHeader,
|
|
24
|
-
summarizeAgentSurfaceBrief,
|
|
25
|
-
AGENT_SURFACE_BRIEF_MAX,
|
|
26
22
|
} from '../../runtime/shared/tool-surface.mjs';
|
|
27
|
-
import {
|
|
23
|
+
import { deriveToolCardModel } from '../../runtime/shared/tool-card-model.mjs';
|
|
28
24
|
import {
|
|
29
25
|
MIN_RESULT_LINE_CHARS,
|
|
30
26
|
RESULT_LINE_HARD_MAX,
|
|
@@ -33,36 +29,13 @@ import {
|
|
|
33
29
|
safeInlineText,
|
|
34
30
|
normalizeCountMap,
|
|
35
31
|
truncateToWidth,
|
|
36
|
-
shellResultElapsed,
|
|
37
|
-
normalizeTerminalStatus,
|
|
38
32
|
resultTerminalStatus,
|
|
39
33
|
stripLeadingStatusMarkerLines,
|
|
40
34
|
stripLeadingStatusMarkerFromText,
|
|
41
35
|
} from './tool-execution/text-format.mjs';
|
|
42
36
|
import {
|
|
43
37
|
SKILL_SURFACE_NAMES,
|
|
44
|
-
isShellTool,
|
|
45
|
-
shellDisplayStatus,
|
|
46
|
-
shellHeader,
|
|
47
38
|
isAgentTool,
|
|
48
|
-
isBackgroundTaskTool,
|
|
49
|
-
agentResponseTitle,
|
|
50
|
-
agentActionTitle,
|
|
51
|
-
agentActionSummary,
|
|
52
|
-
hasAgentResponseResult,
|
|
53
|
-
resolveBackgroundTaskMeta,
|
|
54
|
-
backgroundTaskElapsed,
|
|
55
|
-
prefixElapsed,
|
|
56
|
-
mergeTerminalDetail,
|
|
57
|
-
shouldPrefixSyncElapsed,
|
|
58
|
-
backgroundTaskResultTitle,
|
|
59
|
-
backgroundTaskActionTitle,
|
|
60
|
-
backgroundTaskFailureDetail,
|
|
61
|
-
backgroundTaskDetail,
|
|
62
|
-
isBackgroundTaskResponseArgs,
|
|
63
|
-
genericCompletedDetail,
|
|
64
|
-
toolSearchLoadedSummary,
|
|
65
|
-
agentTerminalDetail,
|
|
66
39
|
clampFailureCount,
|
|
67
40
|
toolStatusColor,
|
|
68
41
|
} from './tool-execution/surface-detail.mjs';
|
|
@@ -77,15 +50,6 @@ const TOOL_PENDING_SHOW_DELAY_MS = 1000;
|
|
|
77
50
|
// One shared-tick cadence covers both the 500ms blink and per-second elapsed;
|
|
78
51
|
// finer than either boundary so both stay crisp off a single timer.
|
|
79
52
|
const TOOL_ANIM_TICK_MS = TOOL_BLINK_MS;
|
|
80
|
-
function statusCopy(name, label, count, doneCount, pending, isError, args = {}) {
|
|
81
|
-
// No stableVerbWidth padding: it padded the done verb to the active ("-ing")
|
|
82
|
-
// width, which Ink trims at the line END (vendor output trimEnd) so it never
|
|
83
|
-
// stabilized the pending→done flip — it only left an UGLY mid-header gap
|
|
84
|
-
// ("Searched 1 pattern", "Read 1 file"). The header is wrap="truncate"
|
|
85
|
-
// behind a fixed gutter and the fullscreen full-clear repaints the row, so
|
|
86
|
-
// dropping the pad just normalizes the spacing.
|
|
87
|
-
return formatToolActionHeader(name, args, { pending, count });
|
|
88
|
-
}
|
|
89
53
|
export function ToolExecution({ name, args, result, rawResult, isError, errorCount, callErrorCount, exitErrorCount, expanded, columns = 80, attached = false, count = 1, completedCount = 0, startedAt = 0, completedAt = 0, aggregate = false, categories = {}, doneCategories = null, headerFinalized = true, deferredDisplayReady = false, agentResponseAggregate = false }) {
|
|
90
54
|
const rowWidth = Math.max(1, Number(columns || 80));
|
|
91
55
|
const groupCount = Math.max(1, Number(count || 1));
|
|
@@ -284,104 +248,52 @@ export function ToolExecution({ name, args, result, rawResult, isError, errorCou
|
|
|
284
248
|
}
|
|
285
249
|
|
|
286
250
|
// ── Normal (non-aggregate) tool card ────────────────────────────
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
? resolveBackgroundTaskMeta(parsedArgs, rt || '')
|
|
292
|
-
: null;
|
|
293
|
-
const backgroundError = backgroundMeta?.error || parsedArgs?.error || '';
|
|
294
|
-
const errorOnlyResult = Boolean(rt) && isBackgroundErrorOnlyBody(rt, backgroundError);
|
|
295
|
-
const backgroundResultText = backgroundMeta?.hasResponse ? backgroundMeta.body : '';
|
|
296
|
-
const displayedResultText = backgroundResultText || (errorOnlyResult ? '' : (rt || ''));
|
|
297
|
-
const hasDisplayResult = Boolean(String(displayedResultText || '').trim());
|
|
298
|
-
const displayedResultBodyText = stripLeadingStatusMarkerFromText(displayedResultText);
|
|
299
|
-
const hasDisplayBody = Boolean(String(displayedResultBodyText || '').trim());
|
|
300
|
-
const lines = displayedResultBodyText ? displayedResultBodyText.split('\n') : [];
|
|
301
|
-
const totalLines = lines.length;
|
|
302
|
-
// Semantic one-line summary derived purely from name/args/result text.
|
|
303
|
-
// Shown in the collapsed, non-error view in place of the raw result block.
|
|
304
|
-
// Grouped cards ("Searched N files" / "Read N files") get the same treatment
|
|
305
|
-
// as single calls: a one-line semantic summary stands in for the raw block.
|
|
306
|
-
const resultSummary = !pending && hasDisplayBody
|
|
307
|
-
? surfaceSummarizeToolResult(name, args, displayedResultBodyText, isError)
|
|
308
|
-
: null;
|
|
309
|
-
// Same fit budget fitResultLine() uses, to detect a line that will be clipped.
|
|
251
|
+
// Single source: the shared collapsed-card derivation (labels, casing,
|
|
252
|
+
// status merging, detail row) consumed by BOTH the TUI and the desktop
|
|
253
|
+
// renderer (apps/desktop TranscriptView ToolCard). Width fitting, theme
|
|
254
|
+
// colors, blink, and expansion handling stay TUI-side below.
|
|
310
255
|
const maxResultChars = Math.min(RESULT_LINE_HARD_MAX, Math.max(MIN_RESULT_LINE_CHARS, Number(columns || 80) - 7));
|
|
256
|
+
const model = deriveToolCardModel({
|
|
257
|
+
name,
|
|
258
|
+
args,
|
|
259
|
+
result,
|
|
260
|
+
rawResult,
|
|
261
|
+
isError,
|
|
262
|
+
errorCount,
|
|
263
|
+
callErrorCount,
|
|
264
|
+
exitErrorCount,
|
|
265
|
+
count: displayGroupCount,
|
|
266
|
+
completedCount: doneCount,
|
|
267
|
+
startedAt,
|
|
268
|
+
completedAt,
|
|
269
|
+
headerFinalized,
|
|
270
|
+
nowMs,
|
|
271
|
+
}, { truncate: truncateToWidth, maxResultChars });
|
|
272
|
+
const {
|
|
273
|
+
labelText,
|
|
274
|
+
summaryText,
|
|
275
|
+
headerFailureText: headerFailureStatus,
|
|
276
|
+
detailLine: collapsedDetailLine,
|
|
277
|
+
detailIsPlaceholder,
|
|
278
|
+
terminalStatus,
|
|
279
|
+
normalizedName,
|
|
280
|
+
isShellSurface,
|
|
281
|
+
isAgentSurfaceCard,
|
|
282
|
+
isAgentResponse,
|
|
283
|
+
isBackgroundMetadataResult,
|
|
284
|
+
hasDisplayResult,
|
|
285
|
+
hasDisplayBody,
|
|
286
|
+
displayedResultBodyText,
|
|
287
|
+
firstResultLine,
|
|
288
|
+
totalLines,
|
|
289
|
+
resultSummary,
|
|
290
|
+
shellCollapsedSummary,
|
|
291
|
+
toolArgPath,
|
|
292
|
+
} = model;
|
|
293
|
+
const lines = displayedResultBodyText ? displayedResultBodyText.split('\n') : [];
|
|
311
294
|
const resultColor = theme.text;
|
|
312
|
-
const firstResultLine = hasDisplayResult ? String(lines[0] ?? '') : '';
|
|
313
295
|
const firstResultLineClipped = hasDisplayBody && stringWidth(firstResultLine) > maxResultChars;
|
|
314
296
|
const hasHiddenDetail = !pending && hasDisplayBody && (totalLines > 1 || firstResultLineClipped || Boolean(resultSummary));
|
|
315
|
-
const shellStatus = isShellSurface ? shellDisplayStatus({ pending, failedCount, exitFailedCount, isError, result: displayedResultText }) : '';
|
|
316
|
-
const shellElapsed = isShellSurface ? (shellResultElapsed(displayedResultText) || elapsed) : '';
|
|
317
|
-
const backgroundElapsed = backgroundMeta
|
|
318
|
-
? backgroundTaskElapsed(backgroundMeta, elapsed)
|
|
319
|
-
: (isBackgroundTaskTool(normalizedName) ? backgroundTaskElapsed(parsedArgs, elapsed) : '');
|
|
320
|
-
|
|
321
|
-
const toolArgPath = parsedArgs?.path ?? parsedArgs?.file_path ?? parsedArgs?.file ?? '';
|
|
322
|
-
// Audit HIGH: on a FAILED view_image the path detail used to win over the
|
|
323
|
-
// error cause (nonShellDetail order puts imageDetail before genericDetail),
|
|
324
|
-
// so the card showed the filename instead of why it failed. Suppress the
|
|
325
|
-
// path detail on error; the error-cause summary/first line takes the row.
|
|
326
|
-
const imageDetail = normalizedName === 'view_image' && toolArgPath && !isError ? String(toolArgPath) : '';
|
|
327
|
-
const isBackgroundResult = !pending && isBackgroundTaskTool(normalizedName) && Boolean(backgroundMeta);
|
|
328
|
-
const isBackgroundResponse = isBackgroundResult && (backgroundMeta?.hasResponse || isBackgroundTaskResponseArgs(normalizedName, parsedArgs));
|
|
329
|
-
const isBackgroundMetadataResult = isBackgroundResult && !isBackgroundResponse && Boolean(backgroundMeta);
|
|
330
|
-
const backgroundMetadataFailureLabel = isBackgroundMetadataResult
|
|
331
|
-
? backgroundTaskFailureDetail(backgroundMeta, parsedArgs)
|
|
332
|
-
: '';
|
|
333
|
-
const backgroundMetadataHeaderFailure = Boolean(backgroundMetadataFailureLabel) && !hasDisplayResult
|
|
334
|
-
? backgroundMetadataFailureLabel
|
|
335
|
-
: '';
|
|
336
|
-
const agentHeaderFailure = !pending && isAgentTool(normalizedName) && isError && parsedArgs?.error && !hasDisplayResult
|
|
337
|
-
? backgroundTaskFailureStatusLabel(parsedArgs?.status, parsedArgs?.error, { surface: 'agent' })
|
|
338
|
-
: '';
|
|
339
|
-
const headerFailureStatus = backgroundMetadataHeaderFailure || agentHeaderFailure || '';
|
|
340
|
-
const agentCompletionDetail = !pending && isAgentTool(normalizedName) && !agentHeaderFailure
|
|
341
|
-
? agentTerminalDetail(parsedArgs?.status, isError, elapsed, parsedArgs?.error)
|
|
342
|
-
: '';
|
|
343
|
-
const agentDetail = !pending && isAgentTool(normalizedName) && !hasDisplayResult
|
|
344
|
-
? agentCompletionDetail
|
|
345
|
-
: '';
|
|
346
|
-
const genericDetail = !pending && !isShellSurface && !agentDetail && !imageDetail && !resultSummary
|
|
347
|
-
? genericCompletedDetail({ normalizedName, label, hasResult, firstResultLine, isError })
|
|
348
|
-
: '';
|
|
349
|
-
const terminalStatus = pending
|
|
350
|
-
? 'running'
|
|
351
|
-
: (shellStatus || normalizeTerminalStatus(backgroundMeta?.status) || normalizeTerminalStatus(parsedArgs?.status) || resultTerminalStatus(displayedResultText) || (isError || failedCount > 0 ? 'failed' : 'completed'));
|
|
352
|
-
const backgroundMetadataDetail = isBackgroundMetadataResult && !backgroundMetadataHeaderFailure
|
|
353
|
-
? backgroundTaskDetail(backgroundMeta, backgroundElapsed, parsedArgs)
|
|
354
|
-
: '';
|
|
355
|
-
const backgroundResponseDetail = isBackgroundResponse && resultSummary
|
|
356
|
-
? prefixElapsed(resultSummary, backgroundElapsed)
|
|
357
|
-
: resultSummary;
|
|
358
|
-
const syncElapsedDetail = !isBackgroundResponse && shouldPrefixSyncElapsed(normalizedName, label)
|
|
359
|
-
? prefixElapsed(backgroundResponseDetail, elapsed)
|
|
360
|
-
: backgroundResponseDetail;
|
|
361
|
-
const nonShellDetail = backgroundMetadataDetail || (/^(Cancelled|Failed|Finished)$/i.test(resultSummary || '') && agentCompletionDetail
|
|
362
|
-
? agentCompletionDetail
|
|
363
|
-
: syncElapsedDetail) || agentDetail || imageDetail || genericDetail;
|
|
364
|
-
// A pending non-aggregate tool used to drop its detail row entirely
|
|
365
|
-
// (collapsedDetail = ''), so the card rendered as a single header row. But
|
|
366
|
-
// estimateTranscriptItemRows() in App.jsx reserves 2 rows for a collapsed
|
|
367
|
-
// non-aggregate tool (1 only for skill surfaces). That left a 1-row gap that
|
|
368
|
-
// closed the instant the result landed — the surviving "line-jump". Reserve the same
|
|
369
|
-
// dim placeholder detail row the aggregate card uses (`Running`) for the whole
|
|
370
|
-
// pending lifecycle so the height stays fixed at header + one detail row and
|
|
371
|
-
// the final summary just fills in place. Skill surfaces collapse to a single
|
|
372
|
-
// row in BOTH the estimate and the render (visibleDetailLines drops the row
|
|
373
|
-
// for isSkillSurface below), so they get no placeholder.
|
|
374
|
-
const pendingDetailPlaceholder = pending && !isSkillSurface
|
|
375
|
-
? (elapsed ? `Running · ${elapsed}` : 'Running')
|
|
376
|
-
: '';
|
|
377
|
-
const shellCollapsedSummary = isShellSurface && !pending && hasDisplayResult
|
|
378
|
-
? (resultSummary || truncateToWidth(firstResultLine, Math.min(120, maxResultChars)))
|
|
379
|
-
: resultSummary;
|
|
380
|
-
const collapsedDetail = pending
|
|
381
|
-
? pendingDetailPlaceholder
|
|
382
|
-
: isShellSurface
|
|
383
|
-
? prefixElapsed(mergeTerminalDetail(shellStatus, shellCollapsedSummary), shellElapsed)
|
|
384
|
-
: mergeTerminalDetail(terminalStatus, nonShellDetail);
|
|
385
297
|
const backgroundMetadataExpandable = isBackgroundMetadataResult && hasRawResult && !pending;
|
|
386
298
|
const showRawResult = expanded && (hasDisplayBody || hasRawResult)
|
|
387
299
|
&& (!isBackgroundMetadataResult || hasRawResult);
|
|
@@ -389,47 +301,11 @@ export function ToolExecution({ name, args, result, rawResult, isError, errorCou
|
|
|
389
301
|
? (agentResponseAggregate && hasRawResult
|
|
390
302
|
? stripLeadingStatusMarkerLines(rawRt.split('\n'))
|
|
391
303
|
: (hasDisplayBody ? lines : (rawRt ? stripLeadingStatusMarkerLines(rawRt.split('\n')) : [])))
|
|
392
|
-
: (
|
|
393
|
-
const isPendingPlaceholderDetail = !showRawResult &&
|
|
304
|
+
: (collapsedDetailLine ? [collapsedDetailLine] : []);
|
|
305
|
+
const isPendingPlaceholderDetail = !showRawResult && detailIsPlaceholder;
|
|
394
306
|
const detailColor = isPendingPlaceholderDetail ? theme.subtle : theme.text;
|
|
395
|
-
|
|
396
|
-
const
|
|
397
|
-
const isAgentResponse = isAgentResult && hasAgentResponseResult(rt);
|
|
398
|
-
const isAgentSurfaceCard = isAgentTool(normalizedName);
|
|
399
|
-
const agentSurfaceBriefRaw = isAgentSurfaceCard && !showRawResult
|
|
400
|
-
? summarizeAgentSurfaceBrief(name, parsedArgs, displayedResultText || '', { isError, isResponse: isAgentResponse })
|
|
401
|
-
: '';
|
|
402
|
-
const agentSurfaceBrief = agentSurfaceBriefRaw
|
|
403
|
-
? truncateToWidth(agentSurfaceBriefRaw, Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars))
|
|
404
|
-
: '';
|
|
405
|
-
// Skill loads carry the skill name in the header already
|
|
406
|
-
// ("Loaded 1 skill (name)"); the collapsed detail row just repeats it, so
|
|
407
|
-
// drop it and keep the card a single line. Expanding (ctrl+o) still shows the
|
|
408
|
-
// full skill body via the raw-result path.
|
|
409
|
-
// Agent spawn/send/response cards show a tight brief under the ⎿ gutter when
|
|
410
|
-
// collapsed; ctrl+o expand still surfaces the full body.
|
|
411
|
-
let visibleDetailLines = detailLines;
|
|
412
|
-
if (isSkillSurface && !showRawResult) {
|
|
413
|
-
// Audit HIGH: a FAILED skill load used to drop its detail row with the
|
|
414
|
-
// success path, hiding the one-line cause entirely. Keep the detail row
|
|
415
|
-
// when the call errored; only the redundant success repeat is dropped.
|
|
416
|
-
visibleDetailLines = isError && collapsedDetail ? [collapsedDetail] : [];
|
|
417
|
-
} else if (isBackgroundMetadataResult && backgroundMetadataHeaderFailure && !showRawResult) {
|
|
418
|
-
visibleDetailLines = [];
|
|
419
|
-
} else if (isAgentSurfaceCard && !showRawResult) {
|
|
420
|
-
// Agent cards collapse to a SINGLE header row like skill surfaces. Keep the
|
|
421
|
-
// ⎿ detail row ONLY when it carries failure info: the call errored, or the
|
|
422
|
-
// brief/summary reads as a failure/cancel. A header-failure-only card (no
|
|
423
|
-
// brief) shows the cause in the header, so it stays a single row too.
|
|
424
|
-
// Expanded (ctrl+o raw) still flows through the showRawResult path above.
|
|
425
|
-
const agentDetailFallback = collapsedDetail
|
|
426
|
-
|| (pending ? (pendingDetailPlaceholder || 'Running') : 'Finished');
|
|
427
|
-
const agentDetailLine = agentSurfaceBrief
|
|
428
|
-
|| truncateToWidth(String(agentDetailFallback), Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars));
|
|
429
|
-
const agentFailureText = /\b(Cancelled|Canceled|Failed)\b/i.test(agentSurfaceBrief || collapsedDetail || '');
|
|
430
|
-
const keepAgentDetail = (isError || agentFailureText) && !(agentHeaderFailure && !agentSurfaceBrief);
|
|
431
|
-
visibleDetailLines = keepAgentDetail ? [agentDetailLine] : [];
|
|
432
|
-
}
|
|
307
|
+
// Skill/agent collapsed gating lives in the shared model (detailLine).
|
|
308
|
+
const visibleDetailLines = detailLines;
|
|
433
309
|
const finalStatusColor = toolStatusColor({ pending, groupCount, callFailedCount, exitFailedCount, terminalStatus });
|
|
434
310
|
const dotColor = finalStatusColor;
|
|
435
311
|
// Agent surface cards use directional markers: `←` for requests going OUT
|
|
@@ -449,31 +325,6 @@ export function ToolExecution({ name, args, result, rawResult, isError, errorCou
|
|
|
449
325
|
const isDirectionalMarker = isAgentResponse || isAgentSurfaceCard;
|
|
450
326
|
const markerText = isDirectionalMarker ? `${markerGlyph} ` : markerGlyph;
|
|
451
327
|
const dotText = pending && !blinkOn ? ' ' : markerText;
|
|
452
|
-
let labelText;
|
|
453
|
-
if (isAgentResponse) labelText = agentResponseTitle(parsedArgs, displayGroupCount);
|
|
454
|
-
else if (isBackgroundResponse) labelText = backgroundTaskResultTitle(normalizedName, backgroundMeta || parsedArgs);
|
|
455
|
-
else if (isBackgroundMetadataResult) labelText = backgroundTaskActionTitle(normalizedName, backgroundMeta);
|
|
456
|
-
else if (isShellSurface) labelText = shellHeader(shellStatus, displayGroupCount);
|
|
457
|
-
else labelText = (isAgentTool(normalizedName) ? agentActionTitle(parsedArgs) : '') || statusCopy(name, label, displayGroupCount, doneCount, headerPending, isError, parsedArgs);
|
|
458
|
-
labelText = safeInlineText(labelText);
|
|
459
|
-
// Show the parenthesized arg summary for grouped cards too, matching single
|
|
460
|
-
// calls so the header carries the same context.
|
|
461
|
-
const toolSearchSummary = !pending && normalizedName === 'load_tool' && hasResult
|
|
462
|
-
? toolSearchLoadedSummary(displayedResultText)
|
|
463
|
-
: '';
|
|
464
|
-
const rawSummaryText = safeInlineText(isAgentResponse || isBackgroundResponse
|
|
465
|
-
? ''
|
|
466
|
-
: toolSearchSummary || (isAgentTool(normalizedName) ? agentActionSummary(parsedArgs, summary) : summary));
|
|
467
|
-
// Drop the parenthesized arg summary when it is a bare "<n> <unit>" count
|
|
468
|
-
// that the header verb already spells out (e.g. header "Searching 6 patterns"
|
|
469
|
-
// + summary "6 patterns"). Multi-arg array calls hit this; single calls keep
|
|
470
|
-
// their descriptive summary ("pattern: \"foo\"") since it never matches the
|
|
471
|
-
// header tail. Channel surfaces are unaffected — they build the summary from
|
|
472
|
-
// summarizeToolArgs directly and never render this header verb.
|
|
473
|
-
const summaryIsHeaderCount = rawSummaryText
|
|
474
|
-
&& /^\d+\s+\S+$/.test(rawSummaryText)
|
|
475
|
-
&& labelText.endsWith(rawSummaryText);
|
|
476
|
-
const summaryText = summaryIsHeaderCount ? '' : rawSummaryText;
|
|
477
328
|
// Agent cards hide their collapsed body but still expose ctrl+o expand only
|
|
478
329
|
// when expanding would actually reveal something: an agent response body, or a
|
|
479
330
|
// multiline / clipped raw result (e.g. the "agents: N …" worker list). A
|