From bdc3e447e981f4971f3bcabbe03af6c21961f093 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 15 Feb 2026 06:15:30 +0000 Subject: [PATCH] refactor(subagents): share formatting helpers --- src/agents/tools/subagents-tool.ts | 55 ++++------------------ src/auto-reply/reply/commands-subagents.ts | 47 ++---------------- src/shared/subagents-format.ts | 41 ++++++++++++++++ 3 files changed, 55 insertions(+), 88 deletions(-) create mode 100644 src/shared/subagents-format.ts diff --git a/src/agents/tools/subagents-tool.ts b/src/agents/tools/subagents-tool.ts index f479fc76b24..be65760d837 100644 --- a/src/agents/tools/subagents-tool.ts +++ b/src/agents/tools/subagents-tool.ts @@ -12,6 +12,11 @@ import { parseAgentSessionKey, type ParsedAgentSessionKey, } from "../../routing/session-key.js"; +import { + formatDurationCompact, + formatTokenShort, + truncateLine, +} from "../../shared/subagents-format.js"; import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/message-channel.js"; import { AGENT_LANE_SUBAGENT } from "../lanes.js"; import { abortEmbeddedPiRun } from "../pi-embedded.js"; @@ -62,48 +67,6 @@ type TargetResolution = { error?: string; }; -function formatDurationCompact(valueMs?: number) { - if (!valueMs || !Number.isFinite(valueMs) || valueMs <= 0) { - return "n/a"; - } - const minutes = Math.max(1, Math.round(valueMs / 60_000)); - if (minutes < 60) { - return `${minutes}m`; - } - const hours = Math.floor(minutes / 60); - const minutesRemainder = minutes % 60; - if (hours < 24) { - return minutesRemainder > 0 ? `${hours}h${minutesRemainder}m` : `${hours}h`; - } - const days = Math.floor(hours / 24); - const hoursRemainder = hours % 24; - return hoursRemainder > 0 ? `${days}d${hoursRemainder}h` : `${days}d`; -} - -function formatTokenShort(value?: number) { - if (!value || !Number.isFinite(value) || value <= 0) { - return undefined; - } - const n = Math.floor(value); - if (n < 1_000) { - return `${n}`; - } - if (n < 10_000) { - return `${(n / 1_000).toFixed(1).replace(/\.0$/, "")}k`; - } - if (n < 1_000_000) { - return `${Math.round(n / 1_000)}k`; - } - return `${(n / 1_000_000).toFixed(1).replace(/\.0$/, "")}m`; -} - -function truncate(text: string, maxLength: number) { - if (text.length <= maxLength) { - return text; - } - return `${text.slice(0, maxLength).trimEnd()}...`; -} - function resolveRunLabel(entry: SubagentRunRecord, fallback = "subagent") { const raw = entry.label?.trim() || entry.task?.trim() || ""; return raw || fallback; @@ -510,8 +473,8 @@ export function createSubagentsTool(opts?: { agentSessionKey?: string }): AnyAge const usageText = resolveUsageDisplay(sessionEntry); const status = resolveRunStatus(entry); const runtime = formatDurationCompact(now - (entry.startedAt ?? entry.createdAt)); - const label = truncate(resolveRunLabel(entry), 48); - const task = truncate(entry.task.trim(), 72); + const label = truncateLine(resolveRunLabel(entry), 48); + const task = truncateLine(entry.task.trim(), 72); const line = `${index}. ${label} (${resolveModelDisplay(sessionEntry, entry.model)}, ${runtime}${usageText ? `, ${usageText}` : ""}) ${status}${task.toLowerCase() !== label.toLowerCase() ? ` - ${task}` : ""}`; const view = { index, @@ -543,8 +506,8 @@ export function createSubagentsTool(opts?: { agentSessionKey?: string }): AnyAge const runtime = formatDurationCompact( (entry.endedAt ?? now) - (entry.startedAt ?? entry.createdAt), ); - const label = truncate(resolveRunLabel(entry), 48); - const task = truncate(entry.task.trim(), 72); + const label = truncateLine(resolveRunLabel(entry), 48); + const task = truncateLine(entry.task.trim(), 72); const line = `${index}. ${label} (${resolveModelDisplay(sessionEntry, entry.model)}, ${runtime}${usageText ? `, ${usageText}` : ""}) ${status}${task.toLowerCase() !== label.toLowerCase() ? ` - ${task}` : ""}`; const view = { index, diff --git a/src/auto-reply/reply/commands-subagents.ts b/src/auto-reply/reply/commands-subagents.ts index 8603a11c48e..eb076e5236c 100644 --- a/src/auto-reply/reply/commands-subagents.ts +++ b/src/auto-reply/reply/commands-subagents.ts @@ -27,6 +27,11 @@ import { callGateway } from "../../gateway/call.js"; import { logVerbose } from "../../globals.js"; import { formatTimeAgo } from "../../infra/format-time/format-relative.ts"; import { parseAgentSessionKey } from "../../routing/session-key.js"; +import { + formatDurationCompact, + formatTokenShort, + truncateLine, +} from "../../shared/subagents-format.js"; import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/message-channel.js"; import { stopSubagentsForRequester } from "./abort.js"; import { clearSessionQueues } from "./queue.js"; @@ -46,48 +51,6 @@ const RECENT_WINDOW_MINUTES = 30; const SUBAGENT_TASK_PREVIEW_MAX = 110; const STEER_ABORT_SETTLE_TIMEOUT_MS = 5_000; -function formatDurationCompact(valueMs?: number) { - if (!valueMs || !Number.isFinite(valueMs) || valueMs <= 0) { - return "n/a"; - } - const minutes = Math.max(1, Math.round(valueMs / 60_000)); - if (minutes < 60) { - return `${minutes}m`; - } - const hours = Math.floor(minutes / 60); - const minutesRemainder = minutes % 60; - if (hours < 24) { - return minutesRemainder > 0 ? `${hours}h${minutesRemainder}m` : `${hours}h`; - } - const days = Math.floor(hours / 24); - const hoursRemainder = hours % 24; - return hoursRemainder > 0 ? `${days}d${hoursRemainder}h` : `${days}d`; -} - -function formatTokenShort(value?: number) { - if (!value || !Number.isFinite(value) || value <= 0) { - return undefined; - } - const n = Math.floor(value); - if (n < 1_000) { - return `${n}`; - } - if (n < 10_000) { - return `${(n / 1_000).toFixed(1).replace(/\.0$/, "")}k`; - } - if (n < 1_000_000) { - return `${Math.round(n / 1_000)}k`; - } - return `${(n / 1_000_000).toFixed(1).replace(/\.0$/, "")}m`; -} - -function truncateLine(value: string, maxLength: number) { - if (value.length <= maxLength) { - return value; - } - return `${value.slice(0, maxLength).trimEnd()}...`; -} - function compactLine(value: string) { return value.replace(/\s+/g, " ").trim(); } diff --git a/src/shared/subagents-format.ts b/src/shared/subagents-format.ts new file mode 100644 index 00000000000..94f632a5776 --- /dev/null +++ b/src/shared/subagents-format.ts @@ -0,0 +1,41 @@ +export function formatDurationCompact(valueMs?: number) { + if (!valueMs || !Number.isFinite(valueMs) || valueMs <= 0) { + return "n/a"; + } + const minutes = Math.max(1, Math.round(valueMs / 60_000)); + if (minutes < 60) { + return `${minutes}m`; + } + const hours = Math.floor(minutes / 60); + const minutesRemainder = minutes % 60; + if (hours < 24) { + return minutesRemainder > 0 ? `${hours}h${minutesRemainder}m` : `${hours}h`; + } + const days = Math.floor(hours / 24); + const hoursRemainder = hours % 24; + return hoursRemainder > 0 ? `${days}d${hoursRemainder}h` : `${days}d`; +} + +export function formatTokenShort(value?: number) { + if (!value || !Number.isFinite(value) || value <= 0) { + return undefined; + } + const n = Math.floor(value); + if (n < 1_000) { + return `${n}`; + } + if (n < 10_000) { + return `${(n / 1_000).toFixed(1).replace(/\\.0$/, "")}k`; + } + if (n < 1_000_000) { + return `${Math.round(n / 1_000)}k`; + } + return `${(n / 1_000_000).toFixed(1).replace(/\\.0$/, "")}m`; +} + +export function truncateLine(value: string, maxLength: number) { + if (value.length <= maxLength) { + return value; + } + return `${value.slice(0, maxLength).trimEnd()}...`; +}