pub struct State {Show 21 fields
pub session: Session,
pub turn: TurnState,
pub ui: UiState,
pub mcp: McpState,
pub settings: Config,
pub instructions: Option<LoadedInstructions>,
pub memory: Option<LoadedMemory>,
pub skills: Option<LoadedSkills>,
pub pending_hook_context: Vec<String>,
pub pending_task_notices: Vec<String>,
pub cwd: PathBuf,
pub temp_dir: PathBuf,
pub ids: IdAllocatorBundle,
pub confirm: Option<Confirmation>,
pub pending_approval: VecDeque<PendingApproval>,
pub pending_question: VecDeque<PendingQuestionSet>,
pub runtime: RuntimeState,
pub should_exit: bool,
pub plugin_commands: Vec<PluginCommand>,
pub output_schema: Option<Value>,
pub now: DateTime<Local>,
}Expand description
Root state. The reducer takes State by value, returns a new
State, and emits any side-effects as a Vec<Cmd>. No &mut — a
deliberate choice so tests can diff before/after without aliasing
worries, and so replay (“compute the final State that this Msg log
would produce”) is a straight fold.
Fields§
§session: Session§turn: TurnState§ui: UiState§mcp: McpState§settings: Config§instructions: Option<LoadedInstructions>§memory: Option<LoadedMemory>Durable semantic memory snapshot (auto-derived index + entries),
refreshed per turn like instructions. Its index is injected into the
model prompt alongside project instructions.
skills: Option<LoadedSkills>Discovered SKILL.md playbooks (project/user/plugin) plus the rendered index injected into the model prompt alongside instructions and memory. Loaded once at startup — skills are authored artifacts, not live state.
pending_hook_context: Vec<String>Context strings injected by before_tool_use plugin hooks
(additionalContext), buffered until the next dispatched model
request consumes them (see push_call_model). Byte-capped; transient
(never persisted with the session).
pending_task_notices: Vec<String>One-line notices about the task checklist for the model’s next
request: user /todos edits, vetoed completions, staleness nudges.
Same lifecycle as pending_hook_context (consumed by the next real
dispatch, transient, never persisted).
cwd: PathBufCurrent working directory. Captured once at startup; tools
receive it via ExecContext::workdir and spawned subprocesses
inherit it. Centralized here so tests can inject a fake cwd.
temp_dir: PathBufSystem temp dir, captured once at startup (std::env::temp_dir()).
Pasted-image attachments build their scratch path from it; holding it
here keeps the reducer free of the env read it used to do inline (#54).
ids: IdAllocatorBundle§confirm: Option<Confirmation>When Some, the next render should pop up a modal confirmation
(e.g. “are you sure you want to /clear?”). Cleared by the
reducer when the user answers.
pending_approval: VecDeque<PendingApproval>FIFO queue of tool actions awaiting the user’s inline approval
(interactive ask mode + Auto-mode escalations). The front item is
rendered as a modal; answering it pops the item and emits
Cmd::ResolveApproval, which unblocks the parked tool task. Empty in
headless mode (no broker → the out-of-band /approve flow instead).
pending_question: VecDeque<PendingQuestionSet>FIFO queue of ask_user_question batches awaiting the user’s answers.
The front item renders as a selectable modal; submitting pops it and
emits Cmd::ResolveQuestion, unblocking the parked tool task. Empty in
headless mode (no broker → the tool proceeds without asking).
runtime: RuntimeStateRuntime-only observability state: process registry, provider capability snapshot, and lifecycle timeline. Not sent to the model.
should_exit: boolQuit flag. When set, the main loop drains pending effects and exits. The reducer never panics on its own; it sets this instead.
plugin_commands: Vec<PluginCommand>Prompt-backed slash commands contributed by enabled plugins
(manifest.prompts). Loaded once at startup by the run loop (like
skills); the reducer expands /name args into a normal
Msg::SubmitPrompt, so recordings replay without the plugin
installed. Sorted by name.
output_schema: Option<Value>mermaid run --output-schema: set by the headless driver before the
dedicated formatting turn; build_chat_request copies it onto the
request (dropping all tools for that turn). Never set interactively.
now: DateTime<Local>Wall-clock for the current reducer step, injected as data (Cause 3).
The driver stamps this once per tick — Local::now() live, or the
recorded entry’s ts on replay — before calling update. The
reducer and the transition helpers read state.now instead of
Local::now() / SystemTime::now(), so update(State, Msg) is a pure
function of its inputs: the same (State, Msg) always yields the same
State, and folding a recorded Msg log recomputes State exactly.
Implementations§
Source§impl State
impl State
Sourcepub fn new(
settings: Config,
cwd: PathBuf,
model_id: String,
now: DateTime<Local>,
) -> Self
pub fn new( settings: Config, cwd: PathBuf, model_id: String, now: DateTime<Local>, ) -> Self
Build a fresh state tied to a specific model + project dir.
Pure given its inputs: now seeds the injected clock and derives the
initial conversation’s id/title, so --replay reconstructs the same
starting state from a recorded header. (The one environment read left
is env::temp_dir() — stable within a machine, and only feeds paste
scratch paths.) Nothing here touches the filesystem or tokio.
Sourcepub fn seed_conversation(&mut self, history: ConversationHistory)
pub fn seed_conversation(&mut self, history: ConversationHistory)
Apply a --continue / --sessions seed: replace the fresh
conversation with the loaded history and re-dispatch the terminal
title once. Shared by the live driver and --replay so both
construct the same starting state by definition.
Sourcepub fn is_busy(&self) -> bool
pub fn is_busy(&self) -> bool
True iff the reducer is currently mid-turn. UI uses this for the “⏎ cancels generation” hint and for keybind routing.
Sourcepub fn current_turn_id(&self) -> Option<TurnId>
pub fn current_turn_id(&self) -> Option<TurnId>
The active TurnId, if any turn is in flight. The reducer
filters incoming effect messages by comparing their embedded
TurnId to this value — if the user cancelled and started a
new turn, stale results from the old turn are dropped cleanly.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for State
impl RefUnwindSafe for State
impl Send for State
impl Sync for State
impl Unpin for State
impl UnsafeUnpin for State
impl UnwindSafe for State
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&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
impl<T> DowncastSync for 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