pub struct UiState {Show 31 fields
pub phase: UiPhase,
pub agent_mode: AgentMode,
pub spinner_label: String,
pub spinner_frame: usize,
pub unicode_symbols: bool,
pub total_tokens: usize,
pub prompt_tokens: usize,
pub completion_tokens: usize,
pub cached_tokens: usize,
pub prior_phase: Option<UiPhase>,
pub prior_spinner_label: Option<String>,
pub thinking_idx: usize,
pub turn_started_at: Option<Instant>,
pub phase_started_at: Option<Instant>,
pub last_context: Option<ContextSnapshot>,
pub last_submitted_message: Option<String>,
pub pending_context_render: Option<bool>,
pub pending_images: Vec<ImagePart>,
pub pending_image_hashes: Vec<u64>,
pub pending_image_markers: Vec<usize>,
pub pending_recalled_attachments: Vec<HistoryImageRef>,
pub session_image_count: usize,
pub show_tool_output: bool,
pub show_reasoning: bool,
pub sub_agent_total: usize,
pub sub_agent_done: usize,
pub sub_agent_tasks: Vec<SubAgentTaskInfo>,
pub sub_agent_failed: usize,
pub sub_agent_started_at: Option<Instant>,
pub active_tool_batches: HashMap<String, ActiveToolBatch>,
pub call_id_to_batch: HashMap<String, String>,
}Fields§
§phase: UiPhase§agent_mode: AgentMode§spinner_label: String§spinner_frame: usize§unicode_symbols: boolMirrors TerminalCaps::unicode_symbols — frozen at construction.
When false, tick_spinner and the spinner-label ellipsis fall
back to ASCII so terminals whose font lacks ◐ / … (notably
Windows legacy conhost) don’t show □ tofu.
total_tokens: usize§prompt_tokens: usize§completion_tokens: usize§cached_tokens: usize§prior_phase: Option<UiPhase>When Suspended, holds the phase to restore on resume.
prior_spinner_label: Option<String>While waiting on a tool approval, holds the "Running {Tool}"
label that was active before the prompt opened. on_approval_needed
stashes it here and swaps spinner_label to “Waiting approval”;
on_approval_resolved restores it. Without this, the spinner kept
saying “Running Bash… · 273s” while the agent was actually blocked
on permission.decide().await — looked identical to a real tool
hang.
thinking_idx: usizeRound-robin index into THINKING_LABELS; bumped on each on_submit.
turn_started_at: Option<Instant>When the current turn started. Set by on_submit, cleared on turn-complete / turn-cancelled / error. Used to surface the total wall-clock duration in the TurnComplete event payload.
phase_started_at: Option<Instant>When the current phase began. Reset on every phase transition
(on_submit, on_thinking, on_tool_call_streaming,
on_tool_call_started) so the spinner shows time spent on the
CURRENT operation — Pondering… 12s, Running ReadFile… 4s
— instead of accumulating over the whole turn. Cleared on
turn-complete / turn-cancelled / error so the idle spinner
(rare) doesn’t tick a stale duration.
last_context: Option<ContextSnapshot>Last observed context breakdown. Populated from
AgentEvent::ContextStats — /context renders this. None
before the first turn completes.
last_submitted_message: Option<String>Verbatim text of the message that is currently running. Set
on every submit, cleared on turn-complete. When the user hits
Ctrl+C / Esc mid-stream the streaming-key handler takes this
and restores it to the input buffer so the cancelled message
can be edited + resent without re-typing. None between
turns and after any successful completion.
pending_context_render: Option<bool>/context dispatched a RefreshContextStats command and is
waiting for the resulting rich ContextStats event to render the
report. Some(show_prompt) until the next rich emission lands;
cleared after the render fires. Prevents stale-cache renders
without forcing /context to block synchronously on the agent
loop. The bool is the prompt sub-arg (include full system
prompt body).
pending_images: Vec<ImagePart>Images pasted from clipboard (Ctrl+V) waiting to be sent with the next user message. Drained on submit.
pending_image_hashes: Vec<u64>Parallel to pending_images — content fingerprint of each pasted
image’s raw RGBA bytes. Used by the right-aligned status hint to
suppress Image in clipboard · ctrl+v to paste once the clipboard
content matches an already-attached image (avoids dup paste prompts),
while still surfacing the hint when the user copies a new image
after pasting an earlier one. Cleared together with pending_images
on submit.
pending_image_markers: Vec<usize>Parallel to pending_images — the marker number N originally
printed for each image at paste time. Submit-time matching does
line.contains("[Image #N]") against this number to decide
whether the image survived editing. Must NOT be i + 1 from the
vec position — once session_image_count became monotonic across
turns, paste-time numbers diverge from positional indices, and
using the index dropped images on every retry that wasn’t the
first paste of the session.
pending_recalled_attachments: Vec<HistoryImageRef>Image attachments to re-attach when the user submits a recalled
history entry. Populated by the up-arrow handler from the
recalled HistoryEntry::images; drained on submit by the
hydrate prelude in event_loop/mod.rs. Lazy by design — disk
reads happen at submit time, not on every navigation.
session_image_count: usizeMonotonic counter for the [Image #N] marker shown in the input
buffer + scrollback. Incremented on every paste and NEVER reset
across turns — so two images pasted in different turns get
distinct labels (e.g. [Image #1] in turn 1, [Image #2] in
turn 2). Without this, both turns’ first paste would both render
as [Image #1], making it ambiguous which image a later
reference points at when scrolling back.
show_tool_output: boolWhether to show real-time tool output (e.g., bash stdout/stderr). Toggled by Ctrl+O. When false (default), tool output is hidden during execution and only shown in the final result.
show_reasoning: boolWhether to show LLM reasoning/thinking content (e.g., DeepSeek-R1,
MiniMax-M2.7). Toggled by Ctrl+O together with show_tool_output.
When false (default), reasoning content is hidden during streaming.
sub_agent_total: usizeNumber of fork sub-agents currently dispatched. While > 0, the
foreground turn is blocked awaiting pool.execute_all — there’s
no fresh tool / think event to update the spinner, so without an
override the label stays frozen on the last tool name (e.g.
“Running ReadFile… 82s”) for the entire pool duration. Cleared
on SubAgentDispatchEnd.
sub_agent_done: usizeHow many sub-agents in the current dispatch have reported a
terminal status (done / failed / timeout). Updated by
on_sub_agent_settled. Reset to 0 on each new dispatch.
sub_agent_tasks: Vec<SubAgentTaskInfo>Per-task descriptors (path + dedup suffix) for the active
dispatch. Indexed identically to the tasks field on
AgentEvent::SubAgentDispatchStart so the UI can look up a
child’s display path from the index field on Started/Done/
Failed events. Cleared on on_sub_agent_dispatch_end.
sub_agent_failed: usizeNumber of failed sub-agents in the current dispatch — tracked
separately from sub_agent_done so the aggregate summary can
distinguish “6/7 ok · 1 fail” from “7/7 ok”. Reset on each new
dispatch.
sub_agent_started_at: Option<Instant>Wall-clock start of the current dispatch. Used to render the
elapsed-time figure on the SubAgentDispatchEnd aggregate
summary line. Cleared with the rest of the dispatch state.
active_tool_batches: HashMap<String, ActiveToolBatch>Active tool batches, keyed by batch_id. Populated on
ToolBatchStarted and cleared on ToolBatchCompleted. Used by
per-call event handlers to detect “this ToolCallStarted/Result
belongs to an active batch” and skip the standalone row render
(the batch header already represents it).
call_id_to_batch: HashMap<String, String>Reverse map call_id → batch_id for O(1) lookup when a per-call
event arrives. Mirrors active_tool_batches membership; cleared
together.
Implementations§
Source§impl UiState
impl UiState
pub fn new() -> Self
Sourcepub fn with_unicode(unicode_symbols: bool) -> Self
pub fn with_unicode(unicode_symbols: bool) -> Self
Construct a UiState with an explicit Unicode capability.
Production code calls this from App::new with the value the
terminal-capability probe produced; tests stick with new().
Sourcepub fn ellipsis(&self) -> &'static str
pub fn ellipsis(&self) -> &'static str
Single-character horizontal ellipsis (…, U+2026) when Unicode
is available, three ASCII dots (...) otherwise. Used by the
spinner label and any other “still working…” suffix.
Sourcepub fn on_context_stats(
&mut self,
system_tokens: usize,
sent_tokens: usize,
tool_defs_tokens: usize,
cold_zone_tokens: usize,
total_messages: usize,
ctx_window: usize,
ctx_name: &str,
system_prompt: &str,
)
pub fn on_context_stats( &mut self, system_tokens: usize, sent_tokens: usize, tool_defs_tokens: usize, cold_zone_tokens: usize, total_messages: usize, ctx_window: usize, ctx_name: &str, system_prompt: &str, )
Merge one AgentEvent::ContextStats emission into the cached
snapshot. The agent side fires two emissions per turn: one narrow
(from TurnRunner) and one rich (from handle_send_message).
Each leaves the fields it doesn’t know at 0 / empty — we keep the
most-recent non-zero value per field so either order works.
Sourcepub fn turn_elapsed(&self) -> Option<Duration>
pub fn turn_elapsed(&self) -> Option<Duration>
Elapsed wall time since the current turn began, if a turn is active. Returns None when idle.
Sourcepub fn phase_elapsed(&self) -> Option<Duration>
pub fn phase_elapsed(&self) -> Option<Duration>
Elapsed wall time since the current phase began. The spinner
uses this so its · 12s suffix shows time on the current
operation (LLM round-trip / tool execution), not cumulative
turn time. Falls back to turn_elapsed() when no phase
transition has fired yet — defensive, should not normally
happen since on_submit seeds both.
pub fn on_submit(&mut self)
pub fn on_turn_complete(&mut self)
pub fn on_turn_cancelled(&mut self)
pub fn on_error(&mut self)
Sourcepub fn on_tool_call_started(&mut self, name: &str)
pub fn on_tool_call_started(&mut self, name: &str)
Set the spinner label to "Running {name}" (no trailing ellipsis —
the renderer appends ... uniformly so it looks right even when
the elapsed-time suffix is appended). Resets the phase clock so
the spinner timer starts fresh on this tool execution.
pub fn on_tool_call_streaming(&mut self, name: &str)
pub fn on_thinking(&mut self)
Sourcepub fn on_sub_agent_dispatch_start(&mut self, tasks: Vec<SubAgentTaskInfo>)
pub fn on_sub_agent_dispatch_start(&mut self, tasks: Vec<SubAgentTaskInfo>)
Begin a fork dispatch. Stores the per-task descriptors so the UI
can look up each child’s display path + dedup-suffix by index
when a SubAgentTaskStarted/Done/Failed event arrives — the
previous flow flattened identical basenames (tunnel.rs × 3)
into indistinguishable rows. Also overrides the foreground
spinner label since pool.execute_all blocks the loop.
Sourcepub fn on_sub_agent_task_done(&mut self)
pub fn on_sub_agent_task_done(&mut self)
Mark one sub-agent as completed (success). Late events after
on_sub_agent_dispatch_end are no-ops — sub_agent_total == 0
is the gate.
Sourcepub fn on_sub_agent_task_failed(&mut self)
pub fn on_sub_agent_task_failed(&mut self)
Mark one sub-agent as failed (error / timeout / no-edit).
Increments BOTH the done and failed counters — for the spinner
label done is “settled” regardless of outcome, but the
aggregate emitted on dispatch_end needs the success/fail split.
Sourcepub fn on_sub_agent_dispatch_end(&mut self)
pub fn on_sub_agent_dispatch_end(&mut self)
End the dispatch — clears descriptors so subsequent thinks/tools
resume normal label behaviour. The next on_thinking /
on_tool_call_started will overwrite spinner_label; we leave it
alone here so the final “N/N” stays visible until the next phase.
The success/fail split is preserved long enough for the event
loop to render the aggregate summary line, then cleared.
Sourcepub fn on_approval_needed(&mut self, display_tool: &str)
pub fn on_approval_needed(&mut self, display_tool: &str)
display_tool is the already-PascalCased name (e.g. "Bash",
"ReadFile") — same form on_tool_call_started writes into
spinner_label. Stashed so on_approval_resolved can put the
label back when execution resumes.
pub fn on_approval_resolved(&mut self)
pub fn on_suspend(&mut self)
pub fn on_resume(&mut self)
Sourcepub fn next_done_label(&mut self) -> &'static str
pub fn next_done_label(&mut self) -> &'static str
Pick (and advance) a playful “done” phrase for the turn separator.
Sourcepub fn toggle_tool_output(&mut self)
pub fn toggle_tool_output(&mut self)
Toggle real-time tool output and reasoning visibility. Both are controlled by Ctrl+O (verbose mode).
Sourcepub fn toggle_verbose(&mut self)
pub fn toggle_verbose(&mut self)
Toggle verbose mode (alias for toggle_tool_output). Shows/hides both tool output and reasoning content.
pub fn tick_spinner(&mut self) -> &'static str
Trait Implementations§
Auto Trait Implementations§
impl Freeze for UiState
impl RefUnwindSafe for UiState
impl Send for UiState
impl Sync for UiState
impl Unpin for UiState
impl UnsafeUnpin for UiState
impl UnwindSafe for UiState
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> 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