Skip to main content

Msg

Enum Msg 

Source
pub enum Msg {
Show 62 variants Key(Key), Paste(Paste), ClipboardRead(ClipboardRead), SubmitPrompt { text: String, attachment_ids: Vec<u64>, }, Slash(SlashCmd), CancelTurn, ConfirmAccepted, ConfirmDeclined, Quit, RuntimeSignal(RuntimeSignal), StreamText { turn: TurnId, chunk: String, }, StreamReasoning { turn: TurnId, chunk: ReasoningChunk, }, StreamToolCall { turn: TurnId, call: ToolCall, }, ContextUsageEstimated { turn: TurnId, snapshot: ContextUsageSnapshot, }, ProviderContextResolved { model_id: String, model_max: Option<usize>, effective: Option<usize>, source: Option<NumCtxSource>, max_output: Option<usize>, }, OllamaPlacementResolved { model_id: String, size_vram_bytes: u64, total_bytes: u64, suggested_num_ctx: Option<u32>, }, ProviderVisionResolved { model_id: String, supports_vision: Option<bool>, warn: bool, }, BuiltinToolSchemaTokens(usize), CompactionFinished { turn: TurnId, result: CompactionResult, }, CompactionFailed { turn: TurnId, trigger: CompactionTrigger, message: String, kind: StatusKind, }, StreamDone { turn: TurnId, usage: Option<TokenUsage>, provider_continuation: Option<ProviderContinuation>, stop_reason: Option<FinishReason>, }, UpstreamError { turn: TurnId, error: UserFacingError, }, TurnCancelled(TurnId), ToolStarted { turn: TurnId, call_id: ToolCallId, }, ToolProgress { turn: TurnId, call_id: ToolCallId, event: ProgressEvent, }, ToolFinished { turn: TurnId, call_id: ToolCallId, outcome: ToolOutcome, }, ApprovalRequested { turn: TurnId, call_id: ToolCallId, tool: String, risk: String, kind: ApprovalKind, prompt: String, allowlist_scope: String, }, QuestionAsked { turn: TurnId, call_id: ToolCallId, questions: Vec<Question>, }, TasksUpdated { store: TaskStore, }, TaskNotice { text: String, }, McpServerReady { name: String, tools: Vec<McpToolSpec>, }, McpServerErrored { name: String, reason: String, }, McpServerStopped { name: String, }, HookContext { turn: TurnId, texts: Vec<String>, }, InstructionsChanged(Option<LoadedInstructions>), MemoryChanged(Option<LoadedMemory>), SessionSaved, ConversationLoaded(ConversationHistory), ConversationsListed(Vec<ConversationSummary>), ProjectFilesListed(Vec<String>), ScratchpadReady { session_id: String, path: PathBuf, }, RuntimeTasksListed(Vec<TaskRecord>), RuntimeTaskLoaded { task: Option<TaskRecord>, events: Vec<TaskTimelineEvent>, }, RuntimeProcessesListed(Vec<ProcessRecord>), RuntimeText(String), RuntimeApprovalsListed(Vec<ApprovalRecord>), RuntimeCheckpointsListed(Vec<CheckpointRecord>), ForkCheckpointsFound(Vec<CheckpointRecord>), RuntimePluginsListed(Vec<PluginInstallRecord>), ModelPullFinished { model: String, }, ModelPullProgress(String), Tick, Resize { width: u16, height: u16, }, TransientStatus { text: String, }, EditorReturned { text: Option<String>, }, BackgroundAgentStarted { agent_id: String, description: String, }, BackgroundAgentProgress { agent_id: String, activity: String, tokens: usize, }, BackgroundAgentFinished { agent_id: String, description: String, report: String, success: bool, cancelled: bool, usage: Option<TokenUsage>, tokens: usize, duration_secs: u64, }, MouseScroll { delta: i16, }, FocusChanged(bool), OpenImageAt { message_index: usize, image_index: usize, image_number: Option<u64>, }, CopySelection(String),
}
Expand description

Single reducer input. Non-exhaustive is intentional: adding a new variant is a deliberate act that forces every reducer arm to consider it at compile time (the reducer’s match is NOT _ => — see reducer.rs).

Serde derives exist for --record / --replay: every Msg the driver feeds the reducer is serialized to one JSONL line, and replay folds the deserialized stream back through update(). New variants round-trip automatically via the externally-tagged representation — no per-variant recording code to keep in sync.

Variants§

§

Key(Key)

Raw key event from crossterm, after the event source has stripped mouse/resize/paste.

§

Paste(Paste)

A terminal bracketed paste (always text; see Paste).

§

ClipboardRead(ClipboardRead)

Async result of a Cmd::ReadClipboard (Ctrl+V) — image, text, empty, or error. Kept separate from Msg::Paste so the paste-race guard can track exactly these reads (see ClipboardRead).

§

SubmitPrompt

User hit Enter on a non-empty input. The event source has already stripped the slash-command routing.

Fields

§text: String
§attachment_ids: Vec<u64>

Attachment IDs the reducer should consume from state.

§

Slash(SlashCmd)

User ran a slash command (post-routing from app::event_source).

§

CancelTurn

Esc or another explicit cancellation source during an active turn.

§

ConfirmAccepted

Confirmation modal answer.

§

ConfirmDeclined

§

Quit

User wants to exit cleanly (Ctrl+D with empty input, or /quit).

§

RuntimeSignal(RuntimeSignal)

External process lifecycle signal. In raw-mode TUI sessions a typed Ctrl+C still arrives as Msg::Key; this variant covers OS-level SIGINT/SIGTERM/SIGHUP delivered from outside.

§

StreamText

Chunk of assistant text. Append to partial_text.

Fields

§turn: TurnId
§chunk: String
§

StreamReasoning

Chunk of reasoning / thinking content.

Fields

§turn: TurnId
§

StreamToolCall

Model emitted a tool call. Append to the outgoing call list; actual execution dispatches on StreamDone.

Fields

§turn: TurnId
§

ContextUsageEstimated

Effect runner estimated the fully-enriched request context after built-in and MCP tool schemas were attached.

Fields

§turn: TurnId
§

ProviderContextResolved

Effect runner resolved the provider’s context window. For Ollama, model_max is the probed architectural window and effective is the auto-fitted/overridden num_ctx. Model-level metadata (not turn-scoped); model_id is carried so a probe that lands after a /model switch can be dropped instead of overwriting the new model’s window. Drives the /context display + quick-fix.

Fields

§model_id: String
§model_max: Option<usize>
§effective: Option<usize>
§source: Option<NumCtxSource>
§max_output: Option<usize>

The model’s per-response output ceiling when the provider exposes one (/models metadata / documented table). #[serde(default)] so recordings from before this field replay unchanged.

§

OllamaPlacementResolved

Effect runner verified the loaded model’s memory placement after a turn (Ollama /api/ps). size_vram_bytes < total_bytes ⇒ the model spilled to CPU/RAM (slow). Model-level metadata (not turn-scoped); model_id is carried so a probe that lands after a /model switch can be dropped. Drives the offload warning + /context placement line.

Fields

§model_id: String
§size_vram_bytes: u64
§total_bytes: u64
§suggested_num_ctx: Option<u32>

Auto-converge target: largest num_ctx that would fit when the model spilled, or None if it fits / can’t be helped by shrinking.

§

ProviderVisionResolved

Effect runner probed whether the active model can see images (Ollama /api/show capabilities). Model-level metadata (not turn-scoped); model_id is carried so a probe that lands after a /model switch is dropped. warn (set at the trigger site — an image paste, a /model switch with an image staged, or a send carrying images) gates the one-shot no-vision-model notice; the capability snapshot refreshes regardless. supports_vision is None when unknown (non-Ollama, or the probe failed) → never warn.

Fields

§model_id: String
§supports_vision: Option<bool>
§warn: bool
§

BuiltinToolSchemaTokens(usize)

The effect runner’s estimate of the built-in tool-schema token cost it appends to every request during dispatch. Not turn-scoped — the reducer stores it on runtime so /context can fold it into its MCP-only estimate and agree with what dispatch actually decides.

§

CompactionFinished

Context compaction completed and produced a replacement model-visible history.

Fields

§turn: TurnId
§

CompactionFailed

Context compaction failed or no-oped. Manual failures end the compaction turn; auto failures may leave generation running.

Fields

§turn: TurnId
§message: String
§

StreamDone

Stream complete. Carries final token count and opaque provider state that must round-trip on the next request.

Fields

§turn: TurnId
§provider_continuation: Option<ProviderContinuation>
§stop_reason: Option<FinishReason>

Why the model stopped (truncation / content block / normal), when the provider reported it. Drives the truncation status note.

§

UpstreamError

Upstream returned a recoverable or terminal error. Reducer commits an error line and returns to Idle (or surfaces a retry affordance, if recoverable).

Fields

§turn: TurnId
§

TurnCancelled(TurnId)

Terminal event for a cancelled turn. Emitted by the effect runner’s drop_scope once every child task in the turn’s TurnScope has unwound. Reducer transitions Cancelling(id) → Idle when it arrives.

Without this, the reducer relies on the (wrong) side-channel of UpstreamError arriving from a cancelled provider call to exit Cancelling. If the provider task is aborted before it can emit an error, the state would stick in Cancelling forever.

§

ToolStarted

Tool was picked up by the executor — useful for “spinner started” UI transitions.

Fields

§turn: TurnId
§call_id: ToolCallId
§

ToolProgress

Mid-flight progress (streaming subprocess output, byte-count updates, multimodal artifacts, nested subagent activity). Reducer pattern-matches the variant and routes accordingly: text variants update the status line; Artifact with an image/* mime attaches to the in-flight assistant message; Subagent* variants render as indented status.

Fields

§turn: TurnId
§call_id: ToolCallId
§

ToolFinished

Tool finished (one of Finished / Error / Cancelled).

Fields

§turn: TurnId
§call_id: ToolCallId
§outcome: ToolOutcome
§

ApprovalRequested

A gated tool is awaiting the user’s inline approval (interactive ask mode / Auto-mode escalation). The reducer enqueues a modal; the answer flows back as Cmd::ResolveApproval. The tool task is parked until then, so the turn naturally pauses (its outcome slot stays None).

Fields

§turn: TurnId
§call_id: ToolCallId
§tool: String
§risk: String
§prompt: String
§allowlist_scope: String
§

QuestionAsked

The ask_user_question tool is asking the user a batch of questions. The reducer stores a PendingQuestionSet and renders a selectable modal; the answer flows back as Cmd::ResolveQuestion. The tool task is parked until then, so the turn naturally pauses (its outcome slot stays None).

Fields

§turn: TurnId
§call_id: ToolCallId
§questions: Vec<Question>
§

TasksUpdated

The TaskBroker published a full checklist snapshot after a task tool (or /tasks edit) mutated the store. Fire-and-forget — the broker already holds the new truth; the reducer replaces conversation.tasks and diffs old vs new for task_completed hook dispatch. Snapshot (not a diff) so this arm is a plain replace and can never desync. Not turn-scoped: /tasks edits arrive outside any turn, and gating would only let the render copy drift from the broker’s truth.

Fields

§

TaskNotice

A one-line checklist notice for the model’s next request (user /todos edit, vetoed completion). Buffered on state.pending_task_notices; the reducer never turn-gates it.

Fields

§text: String
§

McpServerReady

initialize succeeded; server is ready to dispatch tools.

Fields

§name: String
§

McpServerErrored

Server startup failed OR the child exited with non-zero.

Fields

§name: String
§reason: String
§

McpServerStopped

Fields

§name: String
§

HookContext

Context strings returned by before_tool_use plugin hooks (additionalContext). The reducer buffers them (capped) and the next dispatched model request carries them in the instructions channel, consumed exactly once. Turn-scoped so a stale hook’s context can’t leak into a later run.

Fields

§turn: TurnId
§texts: Vec<String>
§

InstructionsChanged(Option<LoadedInstructions>)

MERMAID.md loaded / changed / removed since last check.

§

MemoryChanged(Option<LoadedMemory>)

Memory files loaded / changed / removed since last check.

§

SessionSaved

save_conversation finished.

§

ConversationLoaded(ConversationHistory)

/load <id> — a saved conversation has been read off disk.

§

ConversationsListed(Vec<ConversationSummary>)

Response to Cmd::ListConversations. Populates the /load picker’s candidate list.

§

ProjectFilesListed(Vec<String>)

Response to Cmd::ListProjectFiles: relative project paths for the @-mention picker (gitignore-aware walk, capped, sorted; directories carry a trailing /).

§

ScratchpadReady

Response to Cmd::EnsureScratchpad: the per-session scratch directory exists on disk at path. Carries the conversation id it was minted for so the reducer can drop a stale ready that raced a /clear or /load — it stamps Session::scratchpad only when the id still matches the live conversation.

Fields

§session_id: String
§path: PathBuf
§

RuntimeTasksListed(Vec<TaskRecord>)

Response to /tasks.

§

RuntimeTaskLoaded

Response to /task <id>.

§

RuntimeProcessesListed(Vec<ProcessRecord>)

Response to /processes.

§

RuntimeText(String)

Generic daemon/runtime text response.

§

RuntimeApprovalsListed(Vec<ApprovalRecord>)

§

RuntimeCheckpointsListed(Vec<CheckpointRecord>)

§

ForkCheckpointsFound(Vec<CheckpointRecord>)

Reply to Cmd::ListForkCheckpoints: file checkpoints anchored past a rewind’s fork point (oldest first). The reducer emits a system notice naming the oldest so the user can /restore files the discarded timeline changed; empty means no notice.

§

RuntimePluginsListed(Vec<PluginInstallRecord>)

§

ModelPullFinished

/model <name> finished pulling (Ollama only).

Fields

§model: String
§

ModelPullProgress(String)

Streaming stdout line from an ollama pull subprocess. Reducer forwards to the status line for the user to watch.

§

Tick

1/60s timer tick. Used for spinner animation + elapsed-time display. Reducer only advances derived fields.

§

Resize

Terminal was resized. Reducer normally no-ops; render consumes.

Fields

§width: u16
§height: u16
§

TransientStatus

Generic user-visible feedback from an async effect handler, routed into the chat transcript. Lets effects surface a result (clipboard read, config saved, plugin install, …) without a bespoke Msg per effect.

Fields

§text: String
§

EditorReturned

The $EDITOR compose round-trip finished (Ctrl+O / /editor). The run loop suspends the TUI, launches the editor, and pushes this with the edited draft — so the recording captures the RESULT and --replay never launches an editor. Some(text) replaces the input buffer (empty = deliberate clear); None = no-op (defensive).

Fields

§

BackgroundAgentStarted

A subagent was detached from its turn via Ctrl+B and keeps running in its own task. Adds a row to the live agent panel registry.

Fields

§agent_id: String
§description: String
§

BackgroundAgentProgress

Throttled live activity from a detached subagent (same discipline as ProgressEvent::Subagent* — never per stream chunk).

Fields

§agent_id: String
§activity: String
§tokens: usize
§

BackgroundAgentFinished

A detached subagent finished. Removes its panel row, folds the child’s spend into the session totals, and delivers the report to the model via the queued-message path.

Fields

§agent_id: String
§description: String
§report: String
§success: bool
§cancelled: bool

The drive ended because its cancel token fired (/agents kill, the agent tool’s kill action). A cancelled child gets a system note but NO queued report — the killer already knows.

§usage: Option<TokenUsage>

Provider-reported usage for the child’s whole drive (None when the provider reported nothing — the display falls back to tokens).

§tokens: usize

Display token count (usage total, or the live estimate).

§duration_secs: u64
§

MouseScroll

Mouse-wheel scroll in the chat pane. Positive delta = scroll toward older messages (up), negative = toward newer (down). The reducer accumulates into ui.mouse_scroll_accum; the render layer diffs it and applies the delta to the ChatWidget’s scroll offset.

Fields

§delta: i16
§

FocusChanged(bool)

The terminal window gained (true) or lost (false) focus, from terminal focus reporting. The reducer records it in ui.terminal_unfocused to gate the attention bell.

§

OpenImageAt

Ctrl+Click on an image thumbnail in the chat pane. The coordinates are absolute screen row/col; the render cache’s ChatState::find_image_at_screen_pos maps them to a (message_index, image_index) pair. The main loop handles the lookup before forwarding this message to the reducer, so by the time the reducer sees it, the target has already been resolved into a base64 payload and this Msg carries the already-decoded image. The reducer just emits Cmd::WriteImageToTemp + Cmd::OpenInSystem.

Fields

§message_index: usize
§image_index: usize
§image_number: Option<u64>

The clicked image’s stable global [Image #N] number, when known. Preferred over the positional pair: the display transcript can be stitched (continuation merge, hidden nudges), so display indices need not match committed history. default so pre-stitch recordings replay.

§

CopySelection(String)

Copy the current chat text selection to the system clipboard. The main loop reads the selected text from the render layer (rstate.chat) and emits this, so the side effect flows through update() — and is recorded for replay — instead of being dispatched out-of-band (#18).

Implementations§

Source§

impl Msg

Source

pub fn turn_id(&self) -> Option<TurnId>

Extract the TurnId for effect-result variants. Returns None for variants that aren’t turn-scoped (user intent, housekeeping, MCP lifecycle). The reducer uses this to short-circuit stale events.

Source

pub fn kind(&self) -> MsgKind

Classification for telemetry / replay tooling. Cheaper than a full Debug string and stable across refactors.

Trait Implementations§

Source§

impl Clone for Msg

Source§

fn clone(&self) -> Msg

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Msg

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Msg

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for Msg

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl Freeze for Msg

§

impl RefUnwindSafe for Msg

§

impl Send for Msg

§

impl Sync for Msg

§

impl Unpin for Msg

§

impl UnsafeUnpin for Msg

§

impl UnwindSafe for Msg

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more