pub enum TurnState {
Idle,
Generating {
id: TurnId,
started: SystemTime,
partial_text: String,
partial_reasoning: String,
tokens: usize,
phase: GenPhase,
provider_continuation: Option<ProviderContinuation>,
pending_tool_calls: Vec<ToolCall>,
continuation: bool,
},
ExecutingTools {
id: TurnId,
started: SystemTime,
calls: Vec<PendingToolCall>,
outcomes: Vec<Option<ToolOutcome>>,
},
Compacting {
id: TurnId,
started: SystemTime,
trigger: CompactionTrigger,
resume_continuation: bool,
},
Cancelling {
id: TurnId,
since: SystemTime,
},
}Expand description
The turn state machine. Each variant carries its own TurnId so
the reducer can cheaply check “is this effect result for the
current turn?” without threading the ID through every match arm.
The ExecutingTools::outcomes: Vec<Option<ToolOutcome>> field is
the architectural payoff: every slot starts None, flips to
Some(outcome) as each tool finishes, and the transition to the
follow-up Generating state requires outcomes to be fully
populated. Statically impossible to “lose” a tool result.
Variants§
Idle
Generating
Fields
started: SystemTimeprovider_continuation: Option<ProviderContinuation>Opaque provider state carried until the assistant message commits.
pending_tool_calls: Vec<ToolCall>Tool calls the model has streamed so far this turn.
StreamToolCall messages push here; StreamDone drains
the vec, allocates PendingToolCall entries, and
transitions to ExecutingTools. When the vec is empty at
stream end, the turn returns to Idle.
continuation: boolTrue when this turn resumes a reply cut by the per-response
output cap (auto-continue). The commit stamps the resulting
message ChatMessageKind::Continuation so the transcript can
stitch it into the previous bubble. Survives an intervening
empty-retry or truncation-recovery compaction so a chain never
loses the marker mid-way.
ExecutingTools
Fields
started: SystemTimeWhen tool execution started, so the status line can show elapsed
time (a long-running command — npm run dev, a slow build — would
otherwise look frozen at 0s).
calls: Vec<PendingToolCall>outcomes: Vec<Option<ToolOutcome>>Compacting
Summarizing history as a step of its own: a manual /compact
(trigger: Manual, ends the turn afterwards) or a truncation recovery
(trigger: TruncationRecovery, resumes the run afterwards). Pre-turn auto
compaction instead runs while Generating because it is preflight for the
same user turn. trigger is what the finished/failed handlers key off.
Fields
started: SystemTimetrigger: CompactionTriggerresume_continuation: boolTrue when the turn that led into this compaction was itself a
continuation (see Generating::continuation): a TruncationRecovery
resume must re-enter Generating with the flag intact or a
continuation chain interrupted by a genuine context-full compaction
would commit its remaining text unmarked.
Cancelling
CancelTurn was dispatched. The reducer has already emitted a
Cmd::CancelScope — now we wait for the final Cancelled /
StreamDone that the effect runner sends back when the scope’s
JoinSet drains. Only then do we transition to Idle.
Stuck in Cancelling too long = effect runner has a bug. UI
surfaces a “cleanup taking a while…” hint after 2s.
Implementations§
Trait Implementations§
Auto Trait Implementations§
impl Freeze for TurnState
impl RefUnwindSafe for TurnState
impl Send for TurnState
impl Sync for TurnState
impl Unpin for TurnState
impl UnsafeUnpin for TurnState
impl UnwindSafe for TurnState
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