pub enum UiLine {
Show 28 variants
Welcome {
model: String,
working_dir: String,
},
User(String),
AssistantText(String),
ReasoningText(String),
AssistantLineBreak,
ToolCall {
name: String,
detail: String,
},
ToolCallInFlight {
id: String,
name: String,
detail: String,
},
ToolCallCommit {
call_id: Option<String>,
},
ToolGroupRender {
batch_id: String,
header: String,
children: Vec<ToolGroupChild>,
},
ToolGroupChildUpdate {
batch_id: String,
call_id: String,
new_text: String,
},
ToolGroupSummary {
text: String,
},
ToolResult {
success: bool,
summary: String,
},
DiffLine {
added: bool,
text: String,
},
DiffBlock(Vec<DiffEntry>),
ApprovalPrompt {
tool: String,
detail: String,
},
Error(String),
Warning(String),
TurnCancelled,
TurnComplete,
Spinner {
frame: &'static str,
label: String,
},
ClearTransient,
InputPrompt {
buf: String,
cursor_byte: usize,
menu: Option<MenuPayload>,
status: StatusLine,
attachments: Vec<usize>,
},
StreamingBox {
buf: String,
cursor_byte: usize,
frame: &'static str,
label: String,
status: StatusLine,
menu: Option<MenuPayload>,
attachments: Vec<usize>,
},
InputCommit,
CommandOutput(String),
ImageAttachment(usize),
VisionPreprocessSuccess {
msg: String,
model: String,
},
TurnSeparator {
label: String,
},
}Expand description
Semantic line to render. Renderer implementations translate this to bytes.
Permanent lines (User, Assistant, ToolCall, ToolResult, Diff, Approval, Error, Blank) all enter scrollback. Spinner and InputPrompt are transient.
Variants§
Welcome
User(String)
AssistantText(String)
ReasoningText(String)
LLM reasoning/thinking content (displayed in gray/dimmed style)
AssistantLineBreak
ToolCall
ToolCallInFlight
Animated tool-call line. Pushed on AgentEvent::ToolCallStarted
instead of the static ToolCall, so the user sees the call land
the moment the model commits to it AND its leading icon ticks in
lockstep with the footer spinner via the live-row mechanism (see
RetainedRenderer::push_or_update_inflight_tool). Switched to a
static ▸ icon by ToolCallCommit once the matching result
lands, freeing the live-row slot for the spinner to resume.
ToolCallCommit
Freeze the most recent ToolCallInFlight row to its final
static ▸ icon. Emitted right before ToolResult so the
bottom body row stops animating exactly when the result is
about to be appended below it.
If call_id is provided, only commits if the inflight_tool matches.
ToolGroupRender
Push a parallel-tool batch as a live multi-row group: one
header line + N child rows (one per tool call), all visible
from the start. Subsequent ToolGroupChildUpdate events find
child rows by call_id and update them in place (CC-style
✓ light-up). The group is “live” only as long as it remains
the bottom of body_lines; any other body push freezes it (in
place forever, but no further child updates take effect).
ToolGroupChildUpdate
Update one child row inside an active live-group. Renderer
finds the row keyed by call_id and CUPs to its terminal
position to rewrite. Falls back to no-op if the group has been
frozen (other content was pushed below it).
ToolGroupSummary
One-shot summary line for a completed tool batch — rendered with bold + brand-color emphasis so it stands out as the “this is what happened” anchor (mirrors CC’s task-completion summary visual). Used by both ToolBatchCompleted and SubAgentDispatchEnd.
ToolResult
DiffLine
DiffBlock(Vec<DiffEntry>)
A batch of diff lines emitted in a single render call. Use this
instead of N individual DiffLine renders when a tool result
carries many changed lines — each DiffLine triggers a full
erase_footer + redraw_footer cycle, so 50 diff lines translate
into 50 footer redraws and tens of KB of ANSI, blocking the
event loop long enough to freeze the spinner. DiffBlock does
one erase + N writes + one redraw.
ApprovalPrompt
Error(String)
Warning(String)
Non-fatal advisory line (yellow). Visually distinct from Error
so the user can tell “we saw something fishy and want you to
know” apart from “the turn died.” Currently used by the OpenAI
provider’s truncation detector.
TurnCancelled
TurnComplete
Spinner
Legacy single-line spinner (kept for tests / PlainRenderer fallback).
During Streaming the event loop emits StreamingBox instead so the
spinner sits ABOVE the input box rather than inside it.
ClearTransient
Clear the current transient line (prepares for a permanent write).
InputPrompt
Draw the input prompt “> “ + current buffer (transient, idle).
When menu is Some, a command palette is drawn above the box.
cursor_byte is a byte offset into buf — the renderer wraps
buf to the available input width and derives the 2D cursor
position (row, col) itself so the input box can grow multi-line
when the user exceeds a single row.
Fields
status: StatusLineattachments: Vec<usize>Marker numbers (N from [Image #N]) that actually have
image bytes ready to ship — either freshly attached this
turn or recalled from cache via arrow-up. Renderers cross-
reference each marker against buf and draw a └ [Image #N]
preview row for the intersection right under the input box,
so users can tell “real attachment” from “literal text” at
a glance, before submit. Empty means no preview rows. Only
the main idle / streaming compose paths populate this; modal
flows that reuse InputPrompt for text entry pass Vec::new().
StreamingBox
Streaming chrome: spinner line above a (possibly multi-line)
input box. Same cursor_byte semantics as InputPrompt.
When menu is Some (user typed / into the type-ahead buffer
mid-stream), the slash-command palette is drawn above the box
in place of the spinner — same rendering path as InputPrompt.
InputCommit
User pressed Enter: commit the current InputPrompt to scrollback.
CommandOutput(String)
Slash-command output (arbitrary text, already sanitised by caller).
ImageAttachment(usize)
Image-attachment echo (└ [Image #N]). Emitted right after the
UiLine::User row that contains the matching [Image #N]
marker, so each renderer can align the └ glyph at the same
column as the [ of the marker in the user message above
(col 2). A dedicated variant rather than CommandOutput so
alignment stays consistent across renderers — retained’s
push_body_text auto-prefixes PAD_COL (2 spaces) but
alt-screen’s push_command_output does not, so the same
CommandOutput payload would land at col 2 in one and col 4
(or col 0) in the other.
VisionPreprocessSuccess
One-line success notice for vision-preprocessor OCR. Renders as
{msg} {model} where msg uses the default text style and
model uses the Muted (gray) role — visually distinct from
failure (yellow ! ...) and from arbitrary command output.
The actual VL description is intentionally NOT shown in the UI;
it still rides into conversation history for the main model.
TurnSeparator
A visible separator between turns: ────── {label} ──────.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for UiLine
impl RefUnwindSafe for UiLine
impl Send for UiLine
impl Sync for UiLine
impl Unpin for UiLine
impl UnsafeUnpin for UiLine
impl UnwindSafe for UiLine
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more