Documentation
¶
Overview ¶
Package cliui hosts the CLI terminal display helpers extracted from cmd/. These files provide the terminal subscriber, tool display, subagent display, and turn statistics functionality used by the agent command modes.
All .go files in this package (other than this doc.go) carry a //go:build !js build constraint and are excluded from the JS/WASM build — the WebUI uses a different rendering path that lives outside this package.
Index ¶
- Constants
- Variables
- func AbbreviatePath(p string, maxLen int) string
- func BuildPromptPrefix(model string) string
- func CompactCost(c float64) string
- func CompactDuration(d time.Duration) string
- func CompactTokens(n int) string
- func ComputeDiffStat(toolName, arguments string) string
- func ComputeEditDiff(oldStr, newStr string, maxLines int) string
- func ComputeWriteFileDiff(content string, maxLines int) string
- func CostPrefix(cost string) string
- func ExtractSubagentTask(argsJSON string) (taskDesc, persona string)
- func FormatCompactDiffLine(toolName, arguments, diffStat string) string
- func FormatResultSize(length int) string
- func FormatRunParallelSubagentsPreview(arguments string) string
- func FormatRunSubagentPreview(chatAgent *agent.Agent, arguments string) string
- func FormatSpawnLine(chatAgent *agent.Agent, depth int, persona string, maxCtx int, taskDesc string) string
- func FormatSubagentCtxSuffix(snap SubagentProgressSnapshot) string
- func FormatSubagentDoneLine(persona, status, reason string, tokens int, cost, elapsedSec float64) string
- func FormatThousands(n int) string
- func FormatTodoListBlock(todosRaw []interface{}) string
- func FormatTodoListPanel(todosRaw []interface{}) string
- func FormatTodoWritePreview(arguments string) string
- func FormatTokensShort(n int) string
- func FormatToolArgPreview(toolName, arguments string, maxArgLen int) string
- func FormatToolEndLine(depth int, persona, icon, toolName, preview string, durationSec float64) string
- func FormatToolPreview(chatAgent *agent.Agent, toolName, arguments string, maxArgLen int) string
- func FormatToolRunLine(depth int, persona, icon, toolName string, count int, argsTrail []string, ...) string
- func FormatToolStartLine(depth int, persona, toolName, preview string) string
- func FormatTurnStatsLine(promptDelta, completionDelta int, costDelta float64, ...) string
- func NoteFirstStreamChunk()
- func NotifyTurnCompletion(chatAgent *agent.Agent, turnStart time.Time, skipPrompt bool)
- func PrintAssistantHeader(model string)
- func PrintPerTurnSummary(chatAgent *agent.Agent, start time.Time, promptBefore, completionBefore int)
- func ReadEventDepth(data map[string]interface{}) int
- func ReadEventInt(data map[string]interface{}, key string) int
- func ReadEventInt64(data map[string]interface{}, key string) int64
- func ReadEventPersona(data map[string]interface{}) string
- func ResetTurnFirstToken()
- func SanitizeArgForPreview(s string) string
- func ShortModelName(model string) string
- func ShouldShowTurnStats() bool
- func StartTerminalToolSubscriber(ctx context.Context, chatAgent *agent.Agent, eventBus *events.EventBus, ...) func()
- func TodoBlockRowCount(todosRaw []interface{}) int
- type SubagentProgressSnapshot
- type TerminalSubscriberState
- func (s *TerminalSubscriberState) HandleAgentMessageEvent(data map[string]interface{}, indicator *console.ActivityIndicator, ...)
- func (s *TerminalSubscriberState) HandleQueryCompletedEvent(data map[string]interface{}, indicator *console.ActivityIndicator)
- func (s *TerminalSubscriberState) HandleQueryStartedEvent(indicator *console.ActivityIndicator)
- func (s *TerminalSubscriberState) HandleSecurityPromptEvent(indicator *console.ActivityIndicator)
- func (s *TerminalSubscriberState) HandleStreamChunkEvent(data map[string]interface{}, indicator *console.ActivityIndicator)
- func (s *TerminalSubscriberState) HandleSubagentActivityEvent(data map[string]interface{}, indicator *console.ActivityIndicator, ...)
- func (s *TerminalSubscriberState) HandleTodoUpdateEvent(data map[string]interface{}, indicator *console.ActivityIndicator, ...)
- func (s *TerminalSubscriberState) HandleToolEndEvent(data map[string]interface{}, chatAgent *agent.Agent, ...)
- func (s *TerminalSubscriberState) HandleToolStartEvent(data map[string]interface{}, chatAgent *agent.Agent, ...)
- func (s *TerminalSubscriberState) IsCompact() bool
- func (s *TerminalSubscriberState) IsVerbose() bool
- func (s *TerminalSubscriberState) MaybeDisplayEditDiff(toolName, argsJSON string)
- func (s *TerminalSubscriberState) ResetSpawnTurn()
- func (s *TerminalSubscriberState) VerboseMaxArgLen() int
- type TodoEntry
- type ToolRunState
Constants ¶
const EditDiffMaxLines = 8
EditDiffMaxLines is the default number of diff lines to show in non-verbose mode. Keep it tight — the user wants a glance, not a wall.
const MaxArgsTrail = 3
MaxArgsTrail caps the per-arg preview list shown in the collapsed line. The earliest entries get dropped — the user usually cares about the most recent few calls in a run.
const SecurityCautionLabel = "⚠️ SECURITY CAUTION"
SecurityCautionLabel is the bracketed label rendered in security caution messages. CLI-B-2 extraction.
const SecurityLoopLabel = "🛑 SECURITY LOOP"
SecurityLoopLabel is the bracketed label rendered in security loop messages. CLI-B-2 extraction.
const VerbosePreviewWidth = 200
VerbosePreviewWidth is the argument-preview truncation width in verbose mode. In verbose mode the width is bumped so power users see more of the path or command.
Variables ¶
var TurnFirstTokenAt int64
TurnFirstTokenAt is set (atomically) to the Unix nano time of the first non-empty stream chunk in the current turn. Read by PrintPerTurnSummary to compute time-to-first-token, then reset to 0 at the start of each turn. Package-level so the streaming callback in SetupAgentEvents (no agent-state to hang it on) can flip it.
Functions ¶
func AbbreviatePath ¶
AbbreviatePath shortens a path while preserving the filename. A path like "webui/src/components/settings/ProviderSettingsTab.tsx" that exceeds maxLen renders as "…/ProviderSettingsTab.tsx" — the user almost always cares about the file at the tail more than the directory chain.
When the path has a separator we always prefer "…/basename" even if the basename itself is still over maxLen: the alternative (tail- truncating the basename) drops the suffix that usually identifies the file type, which is worse than overshooting maxLen by a few chars on a pathological filename. The only path with no separator falls back to a plain tail-truncate.
func BuildPromptPrefix ¶
BuildPromptPrefix returns the interactive REPL prompt for the given model. SP-048-5d. Format: "<model> ▸ " when a model name is available, "sprout> " as the legacy fallback when it isn't.
func CompactDuration ¶
CompactDuration formats a time.Duration compactly.
func ComputeDiffStat ¶
ComputeDiffStat produces a dim "+N -M" diffstat suffix for file-editing tools. For edit_file it counts lines in old_str vs new_str; for write_file it counts all lines as added (new file or full overwrite). Returns "" for non-file tools or when no useful diff can be computed. CLI-UX-3.
func ComputeEditDiff ¶
ComputeEditDiff generates a compact unified diff from the old and new strings for display in the terminal after an edit_file operation.
Shows removed lines in red (-) and added lines in green (+), with up to one context line before and after the changed block. Truncates to maxLines when > 0; pass 0 for unlimited (verbose mode).
func ComputeWriteFileDiff ¶
ComputeWriteFileDiff generates a preview of new file content written via write_file. Shows the first few lines with green (+) markers, truncated per maxLines (0 = unlimited, for verbose mode).
func CostPrefix ¶
CostPrefix returns " · " when cost is non-empty, "" when empty, so the turn-summary line omits the cost segment cleanly for models without pricing.
func ExtractSubagentTask ¶
ExtractSubagentTask parses run_subagent tool arguments and returns (taskDescription, persona). The task description is the first line of the prompt, truncated to 60 chars so the spawn line stays scannable. Returns ("", "") when the args don't contain a usable prompt/persona.
func FormatCompactDiffLine ¶
FormatCompactDiffLine renders the minimal one-liner shown in compact mode for file edits: "edit_file (path.go) +12 -3". Extracts the path from args for context so the user knows which file changed.
func FormatResultSize ¶
FormatResultSize renders a human-readable size string for the number of characters in a tool result. Used by verbose mode to append a dim "· 1.2KB" or "· 450 chars" suffix to tool-end lines. Returns "" for zero-length results so we don't clutter the line with "· 0 chars".
Threshold: >=1000 chars switches to kilobytes (base-1024) with one decimal place; below that we show the raw char count.
func FormatRunParallelSubagentsPreview ¶
FormatRunParallelSubagentsPreview shows the task count so the user knows how many subagents fanned out. No per-task persona since the parallel form doesn't accept per-task persona overrides today; users see the count and infer fan-out from the line.
func FormatRunSubagentPreview ¶
FormatRunSubagentPreview extracts the persona from args and looks up its effective provider/model via the agent's persona resolver. Format:
(coder · anthropic/claude-haiku-4-5)
Falls back to just persona name (or empty) when the lookup fails.
func FormatSpawnLine ¶
func FormatSpawnLine(chatAgent *agent.Agent, depth int, persona string, maxCtx int, taskDesc string) string
FormatSpawnLine renders the one-shot "↳ persona spawned (provider · model · 128k ctx)" line emitted the first time the CLI sees a new (depth, persona) pair in a turn. Indent matches the corresponding tool-line depth so it visually nests under the parent that spawned it. The `maxCtx` argument carries the subagent's model context budget (from monitorProgress's initial emit); 0 means "unknown" and the ctx suffix is dropped — the line degrades to the original "(provider · model)" form.
CLI-UX-11: when taskDesc is non-empty, it's appended after the persona badge so the user sees what the subagent is doing: "↳ coder: refactor auth.go" instead of just "↳ coder".
func FormatSubagentCtxSuffix ¶
func FormatSubagentCtxSuffix(snap SubagentProgressSnapshot) string
FormatSubagentCtxSuffix renders the trailing "· 12.3k/128k ctx" hint appended to depth>0 tool-start lines. Returns "" when no useful numbers are available so the line stays clean during the first tick before any tokens have accumulated.
func FormatSubagentDoneLine ¶
func FormatSubagentDoneLine(persona, status, reason string, tokens int, cost, elapsedSec float64) string
FormatSubagentDoneLine renders the per-subagent completion summary — the closing bracket for the spawn line. Format:
↳ [persona] done · 12,345 tok · $0.0234 · 4.2s ↳ [persona] cancelled (budget_exceeded) · 8,901 tok · $0.0102 · 2.1s
Indents at depth 1 to nest visually under the parent's run_subagent row. Numeric fields are omitted when zero so a no-cost / no-token cancellation stays terse rather than printing "0 tok · $0.0000".
func FormatThousands ¶
FormatThousands renders an integer with comma separators (e.g. 1234567 → "1,234,567"). Negative numbers keep the sign.
func FormatTodoListBlock ¶
func FormatTodoListBlock(todosRaw []interface{}) string
FormatTodoListBlock renders the multi-line todo block printed in the scroll region in response to EventTypeTodoUpdate. The header is a one-line summary (counts by status); the body is one row per item with a status-coded glyph (✓ done, → active, · pending, ⏹ cancelled). Truncates long lists to keep the terminal scannable.
func FormatTodoListPanel ¶
func FormatTodoListPanel(todosRaw []interface{}) string
FormatTodoListPanel renders the todo list inside a box-drawing panel for stronger visual structure (CLI-UX-9). The panel header includes the status counts; the body is the same per-row content as formatTodoListBlock but wrapped in light-vertical borders.
func FormatTodoWritePreview ¶
FormatTodoWritePreview produces the compact tail for the todo_write tool's spinner / collapse line — "(5 tasks · 1 active · 3 done)" — so the user sees the shape of the list at a glance without waiting for the full TodoUpdate block to land. Returns "" when the args are unparseable or empty, matching the contract of the other per-tool preview helpers.
func FormatTokensShort ¶
FormatTokensShort formats a token count compactly: "1234" → "1.2k", "1234567" → "1.2M". Used inside tool/spawn lines where horizontal space is at a premium — the full comma-separated form lives in the "↳ done" line at the end of the subagent run.
func FormatToolArgPreview ¶
FormatToolArgPreview produces a short, single-line preview of a tool's arguments for the activity indicator. The arguments string is the raw JSON the model emitted; we extract whichever field is most informative for the tool at hand. Returns an empty string (no parens) when nothing useful is available. Best-effort — invalid JSON yields no preview.
maxArgLen overrides the per-tool truncation widths when > 0 (used by verbose mode to show longer paths/commands). Pass 0 to use the built-in per-tool defaults documented below.
Per-tool max widths and truncation strategies (when maxArgLen == 0):
- File paths use AbbreviatePath so the filename always survives even when the directory prefix has to be dropped — "…/last/two/seg.go" reads better than "webui/src/components/sett…" where the actual file is lost.
- shell_command / exec preserve more context (80 chars) because the suffix of a command is often the meaningful part (pipes, args).
- Everything else gets the conservative 70-char tail truncation.
func FormatToolEndLine ¶
func FormatToolEndLine(depth int, persona, icon, toolName, preview string, durationSec float64) string
FormatToolEndLine builds the activity-indicator replacement line for a ToolEnd event. Same depth/badge logic as FormatToolStartLine.
func FormatToolPreview ¶
FormatToolPreview produces a short, single-line preview of a tool call for the activity-indicator timeline. For subagent tools (run_subagent, run_parallel_subagents) it surfaces the persona and the resolved provider/model so users can see which subagent — and which underlying model, often a cheaper/faster one than the parent's — is doing the work. For everything else it falls through to FormatToolArgPreview.
maxArgLen overrides the per-tool truncation width when > 0 (verbose mode passes a higher value so power users see more of the path/command). Pass 0 to use the built-in per-tool defaults.
func FormatToolRunLine ¶
func FormatToolRunLine(depth int, persona, icon, toolName string, count int, argsTrail []string, totalSec float64) string
FormatToolRunLine renders a collapsed line for repeated calls of the same tool. Replaces N stacked "✓ read_file (foo.go) · 0.1s" entries with a single "✓ read_file × N (foo.go, bar.go, baz.go) · 0.3s" line updated in place via ActivityIndicator.ReplaceLastN.
argsTrail holds the most recent up-to-3 arg previews so the user can still see what was touched without scrolling through identical entries. totalSec is the cumulative duration across all N calls so the line still surfaces "this batch took a moment" even when each individual call was quick.
func FormatToolStartLine ¶
FormatToolStartLine builds the activity-indicator line for a ToolStart event. At depth 0 it's byte-identical to the pre-SP-051 format (" tool_name(preview)") so primary-agent tool calls render unchanged. At depth >= 1 it adds a depth indent and a colored "[persona]" badge.
func FormatTurnStatsLine ¶
func FormatTurnStatsLine(promptDelta, completionDelta int, costDelta float64, elapsed, ttft time.Duration) string
FormatTurnStatsLine builds the dim single-line turn-summary string. When color is disabled (NO_COLOR), ANSI dim codes are stripped. SP-048-5a.
ttft (time to first token) is rendered as a separate segment when non-zero. Threshold coloring (yellow >2s, red >5s) makes slow provider connections visible at a glance — they're the most common cause of "is sprout stuck?" perception even when the actual model run is fast once it starts streaming.
func NoteFirstStreamChunk ¶
func NoteFirstStreamChunk()
NoteFirstStreamChunk is invoked once per turn from the streaming callback. CompareAndSwap ensures only the very first non-empty chunk updates the timestamp — later chunks are no-ops.
func NotifyTurnCompletion ¶
NotifyTurnCompletion emits a terminal bell and/or OS notification when a turn completes after exceeding the configured minimum duration. Suppressed in non-interactive sessions, when --skip-prompt is set, or for fast turns. SP-070-2.
func PrintAssistantHeader ¶
func PrintAssistantHeader(model string)
PrintAssistantHeader writes the dim "▌ assistant · <model>" header that marks the start of an assistant turn. Honors NO_COLOR via the existing color preference resolver. The brand cyan `▌` aligns visually with the glyph vocabulary in pkg/console; the model name sits in dim grey so the eye is drawn to the bar, not the metadata.
func PrintPerTurnSummary ¶
func PrintPerTurnSummary(chatAgent *agent.Agent, start time.Time, promptBefore, completionBefore int)
PrintPerTurnSummary emits a dim single-line summary of what just happened in the LLM round-trip: input/output tokens consumed, $ spent, elapsed wall time, plus ttft when available. Silent when no tokens were used (e.g. the turn was a slash command or zsh fast path). Only shown when stderr is a TTY (respects NO_COLOR for ANSI codes). SP-048-5a.
func ReadEventDepth ¶
ReadEventDepth reads the subagent_depth from an event payload. Returns 0 for missing or malformed values — matches today's "primary agent" rendering when older events that pre-date SP-051 metadata land in the bus.
func ReadEventInt ¶
ReadEventInt extracts an int from an event payload, tolerating the numeric types the event bus may marshal through (int / int64 / float64 round-trip via JSON).
func ReadEventInt64 ¶
ReadEventInt64 extracts an int64 from an event payload.
func ReadEventPersona ¶
ReadEventPersona reads the active_persona from an event payload, trimmed. Returns "" when absent — which suppresses the persona badge.
func ResetTurnFirstToken ¶
func ResetTurnFirstToken()
ResetTurnFirstToken clears the ttft tracker. Called by the REPL just before submitting a turn so each turn's measurement is independent.
func SanitizeArgForPreview ¶
SanitizeArgForPreview collapses whitespace and strips control characters so the preview always renders on one line inside parentheses.
func ShortModelName ¶
ShortModelName strips the lab/org prefix from a model ID for display. "deepseek-ai/DeepSeek-V4-Flash" → "DeepSeek-V4-Flash" "meta-llama/Llama-3.3-70B-Instruct" → "Llama-3.3-70B-Instruct" "glm-4.6" → "glm-4.6" (no slash, returned as-is)
func ShouldShowTurnStats ¶
func ShouldShowTurnStats() bool
ShouldShowTurnStats returns true when stderr is connected to a TTY. The turn-summary line is written to os.Stderr, so we must check stderr (not stdout) to determine whether it will render cleanly. This matters in piping scenarios like `sprout agent "query" > output.txt` where stdout is piped but stderr is still the terminal. SP-048-5a.
func StartTerminalToolSubscriber ¶
func StartTerminalToolSubscriber(ctx context.Context, chatAgent *agent.Agent, eventBus *events.EventBus, indicator *console.ActivityIndicator, footer *console.StatusFooter) func()
StartTerminalToolSubscriber subscribes a goroutine to the event bus that translates PublishToolStart / PublishToolEnd events into terminal spinner updates and ✓/✗ result lines. Runs until ctx is cancelled.
Tools whose ToolConfig declares Interactive=true (e.g. ask_user) bypass the spinner entirely so their own prompt rendering isn't clobbered.
Also stops the spinner on any prompt-request event (security approval, security prompt, ask_user) so prompts routed through the event bus get clean rendering with no spinner frames overwriting the prompt text. When footer is non-nil, it is refreshed on each ToolEnd so cost / context stay current as tools consume tokens.
The chatAgent reference is used to resolve subagent personas to their effective provider/model so `run_subagent` lines can show which model will actually run the delegated task (subagents often use cheaper or faster models than the parent, and visibility into that matters).
func TodoBlockRowCount ¶
func TodoBlockRowCount(todosRaw []interface{}) int
TodoBlockRowCount returns the number of terminal rows that fmt.Fprintln(os.Stdout, formatTodoListBlock(todosRaw)) will consume. The block string has a header row plus one row per item (each item prefixed by \n). fmt.Fprintln adds a final \n. So the visible rows = strings.Count(block, "\n") + 1.
Types ¶
type SubagentProgressSnapshot ¶
type SubagentProgressSnapshot struct {
TokensUsed int
CtxUsed int
CtxMax int
Iteration int
LastUpdated time.Time
}
SubagentProgressSnapshot is the most-recent live snapshot of a running subagent's token / context usage, refreshed by the runner's monitorProgress ticker (~every 2s). The CLI subscriber appends a compact "· 12.3k/128k ctx" suffix to subsequent tool-start lines fired by the same persona so users see the budget burn in real time, instead of only learning the final numbers in the "completed" line after the subagent has already exited.
type TerminalSubscriberState ¶
type TerminalSubscriberState struct {
// contains filtered or unexported fields
}
TerminalSubscriberState holds all mutable state for the terminal tool subscriber goroutine. Extracted from the closure variables of startTerminalToolSubscriber so the event loop can be broken into focused handler methods.
func NewTerminalSubscriberState ¶
func NewTerminalSubscriberState(configMgr *configuration.Manager) *TerminalSubscriberState
NewTerminalSubscriberState initializes a fresh subscriber state with pre-allocated maps and the config manager for live verbosity reads.
func (*TerminalSubscriberState) HandleAgentMessageEvent ¶
func (s *TerminalSubscriberState) HandleAgentMessageEvent(data map[string]interface{}, indicator *console.ActivityIndicator, footer *console.StatusFooter)
HandleAgentMessageEvent formats and prints an agent message (security caution, security loop, tool error, warning, or generic info) via console.PrintExternal. Breaks the collapse run and refreshes the footer.
func (*TerminalSubscriberState) HandleQueryCompletedEvent ¶
func (s *TerminalSubscriberState) HandleQueryCompletedEvent(data map[string]interface{}, indicator *console.ActivityIndicator)
HandleQueryCompletedEvent processes a QueryCompleted event (CLI-UX-7).
Prints a dim one-line turn summary so the user sees how long the turn took and how much it cost, without the clutter of a full metrics dump. Format:
✓ turn complete · 12.3s · $0.04
Suppressed entirely in compact mode.
func (*TerminalSubscriberState) HandleQueryStartedEvent ¶
func (s *TerminalSubscriberState) HandleQueryStartedEvent(indicator *console.ActivityIndicator)
HandleQueryStartedEvent processes a QueryStarted event (CLI-UX-5).
When the LLM begins "thinking" — the gap between query submission and the first tool or streamed token — we show a contextual "thinking…" spinner so the terminal never looks frozen. The spinner is only started when no tool spinner is already active (the tool line is more informative) and suppressed entirely in compact mode.
The spinner stops naturally when either:
- A StreamChunk with content_type arrives (assistant prose starts) → HandleStreamChunkEvent clears it.
- A ToolStart fires → HandleToolStartEvent clears it and starts the tool spinner.
func (*TerminalSubscriberState) HandleSecurityPromptEvent ¶
func (s *TerminalSubscriberState) HandleSecurityPromptEvent(indicator *console.ActivityIndicator)
HandleSecurityPromptEvent stops the spinner and breaks the collapse run when a prompt is about to render (security approval, security prompt, or ask_user). Subsequent activity re-starts the spinner naturally.
func (*TerminalSubscriberState) HandleStreamChunkEvent ¶
func (s *TerminalSubscriberState) HandleStreamChunkEvent(data map[string]interface{}, indicator *console.ActivityIndicator)
HandleStreamChunkEvent processes a StreamChunk event.
If the chunk carries a content_type (assistant text), it breaks any pending tool-collapse run so the next ToolEnd prints a fresh row.
func (*TerminalSubscriberState) HandleSubagentActivityEvent ¶
func (s *TerminalSubscriberState) HandleSubagentActivityEvent(data map[string]interface{}, indicator *console.ActivityIndicator, footer *console.StatusFooter)
HandleSubagentActivityEvent processes a SubagentActivity event.
"progress" status: cache the snapshot keyed by persona and refresh the footer so fleet-cost stays current. "completed"/"cancelled": emit a done summary line, clear progress cache, break the collapse run, and refresh the footer.
func (*TerminalSubscriberState) HandleTodoUpdateEvent ¶
func (s *TerminalSubscriberState) HandleTodoUpdateEvent(data map[string]interface{}, indicator *console.ActivityIndicator, footer *console.StatusFooter)
HandleTodoUpdateEvent renders the agent's todo list as a styled block in the scroll region. Breaks the collapse run and refreshes the footer.
func (*TerminalSubscriberState) HandleToolEndEvent ¶
func (s *TerminalSubscriberState) HandleToolEndEvent(data map[string]interface{}, chatAgent *agent.Agent, indicator *console.ActivityIndicator, footer *console.StatusFooter)
HandleToolEndEvent processes a ToolEnd event.
Interactive tools are skipped. For other tools: recover args from the ToolStart cache, collapse consecutive identical calls into a single in-place row (Phase 3), or emit a fresh end line. Refreshes the footer.
func (*TerminalSubscriberState) HandleToolStartEvent ¶
func (s *TerminalSubscriberState) HandleToolStartEvent(data map[string]interface{}, chatAgent *agent.Agent, indicator *console.ActivityIndicator)
HandleToolStartEvent processes a ToolStart event.
Interactive tools bypass the spinner entirely. For all other tools: resolve any active reasoning fold, cache args for the matching ToolEnd, announce subagent spawns once per (depth, persona) per turn, and start the activity indicator with a context suffix when progress is available.
In "compact" verbosity mode, the spinner and spawn announcements are suppressed — only error results break the silence.
func (*TerminalSubscriberState) IsCompact ¶
func (s *TerminalSubscriberState) IsCompact() bool
IsCompact reports whether the subscriber should suppress tool chrome (spinner, result lines, todo blocks, subagent announcements). Read live from the config manager on each call so a mid-session /settings change takes effect immediately instead of requiring a restart. Falls back to false (non-compact) when the manager is nil (non-agent callers, tests).
func (*TerminalSubscriberState) IsVerbose ¶
func (s *TerminalSubscriberState) IsVerbose() bool
IsVerbose reports whether the subscriber should show extended detail (full tool arguments, result size suffixes). Read live from the config manager — mirrors IsCompact() — so a mid-session /settings change to "verbose" takes effect immediately without a restart. Falls back to false when the manager is nil (non-agent callers, tests).
func (*TerminalSubscriberState) MaybeDisplayEditDiff ¶
func (s *TerminalSubscriberState) MaybeDisplayEditDiff(toolName, argsJSON string)
MaybeDisplayEditDiff shows a compact diff for file-editing tools (edit_file, write_file). In verbose mode the full diff is shown; in default mode it's truncated to EditDiffMaxLines. Compact mode reaches this only for errors — successes return early with just the diffstat.
func (*TerminalSubscriberState) ResetSpawnTurn ¶
func (s *TerminalSubscriberState) ResetSpawnTurn()
ResetSpawnTurn clears the per-turn spawn dedupe map so the next batch of subagents gets fresh announcements. Called by the REPL loop at the start of each user turn.
func (*TerminalSubscriberState) VerboseMaxArgLen ¶
func (s *TerminalSubscriberState) VerboseMaxArgLen() int
VerboseMaxArgLen returns the argument-preview truncation width to pass to FormatToolPreview/FormatToolArgPreview. In verbose mode the width is bumped so power users see more of the path or command. In default or compact mode it returns 0, which tells the preview functions to use their built-in per-tool defaults.
type TodoEntry ¶
TodoEntry mirrors the internal struct used by both the inline block and the panel renderer so they stay in sync.
func CollectTodos ¶
CollectTodos parses the raw todo event payload into typed items and counts by status. Shared by formatTodoListBlock and formatTodoListPanel.
type ToolRunState ¶
type ToolRunState struct {
Name string
Depth int
Persona string
Count int
ArgsTrail []string // most recent up to MaxArgsTrail entries
TotalMs int64
LastIcon string
LastEnd time.Time
}
ToolRunState tracks a sequence of consecutive identical tool calls so the subscriber can collapse them into a single in-place row (Phase 3 of CLI ergonomics). A run is broken — set to nil — whenever any non-tool event would invalidate the row math: streaming assistant text, a different tool, or a user-prompt boundary.
func (*ToolRunState) AppendArg ¶
func (r *ToolRunState) AppendArg(preview string)
AppendArg adds an argument preview to the args trail, capping it at MaxArgsTrail.