Skip to main content

TurnCtx

Struct TurnCtx 

Source
pub struct TurnCtx<'a, P, T>
where P: LlmProvider + ?Sized, T: ToolExecutor + ?Sized,
{
Show 19 fields pub provider: &'a P, pub tools: &'a T, pub model: &'a str, pub options: &'a RunTurnOptions, pub messages: Vec<Message>, pub outputs: Vec<Message>, pub total_usage: Usage, pub last_stop: Option<StopReason>, pub executed_tools: bool, pub produced_text: bool, pub pending_handoff: Option<HandoffRequest>, pub denied_sigs: HashSet<(String, String)>, pub approved_remaining: HashSet<(String, String, String)>, pub denial_reprompts: usize, pub saw_sig_match_denial: bool, pub grant_replays: Vec<GrantReplayClear>, pub unattended_denials: Vec<UnattendedDenial>, pub escape_hatch_fired: bool, pub delegate_records: Vec<DelegateRecord>,
}
Expand description

The turn’s working state, threaded through each TurnStep.

Owns what were locals in the turn function — the working transcript, the accumulated wire outputs, the folded usage, the last stop reason, and the loop-control flags — and borrows the turn’s immutable inputs (the provider, tool executor, model, and options) for the lifetime 'a so a step can dial the provider without re-plumbing them.

Fields§

§provider: &'a P

The LLM provider the turn dials.

§tools: &'a T

The executor that advertises and runs this turn’s tools.

§model: &'a str

The model identifier for provider requests.

§options: &'a RunTurnOptions

The options the turn was invoked with (streaming channel, decisions).

§messages: Vec<Message>

The working transcript driven through the loop and any post-steps.

§outputs: Vec<Message>

The wire messages produced so far — assistant text and tool results.

§total_usage: Usage

Usage folded across every provider call this turn has made.

§last_stop: Option<StopReason>

Stop reason of the most recent provider step.

§executed_tools: bool

Whether any tool ran this turn (resume pre-pass or the loop).

§produced_text: bool

Whether the model ever emitted user-visible text this turn.

§pending_handoff: Option<HandoffRequest>

The pending handoff request, if the model asked to hand off.

§denied_sigs: HashSet<(String, String)>

STICKY/TERMINAL denials keyed to the tool signature (name + canonical args) rather than the provider call-id. Once a human denies an action, the model can re-emit the SAME logical call with a fresh call-id; a call-id-only check would re-pause and re-prompt for something already rejected. The resume pre-pass seeds this and the in-loop batch records into it, so a matching re-emit is auto-denied (synthetic result) without ever pausing again.

§approved_remaining: HashSet<(String, String, String)>

Approvals still awaiting execution, keyed by the canonicalized (id, name, args) identity (#141). Seeded from RunTurnOptions::approved_call_ids; the resume pre-pass removes each entry it spends so neither the pre-pass nor the loop re-executes an approval the model re-emits. args is canonicalized through canon_args so a re-emit with reordered keys still matches by value.

§denial_reprompts: usize

How many loop iterations have resolved a signature-matched terminal denial — the model retrying an action a human already denied. The first signed denial (by call-id, before any signature is recorded) does not count; only re-emits of an already-denied signature do. Persists across iterations so the stateless CircuitBreaker step can increment it and end the turn once it reaches MAX_DENIAL_REPROMPTS.

§saw_sig_match_denial: bool

Whether the step that just resolved handled a signature-matched terminal denial. The loop republishes it onto the ctx each iteration before the CircuitBreaker step reads it; the step never touches the working state.

§grant_replays: Vec<GrantReplayClear>

Gate clears a remembered passkey grant was solely responsible for (#594), accumulated across the turn’s loop iterations. Each entry is an executed tool call that ran only because a grant kept a capability untrusted content in context would have revoked; the final TurnResult::grant_replays carries them out for the control plane to audit.

§unattended_denials: Vec<UnattendedDenial>

Gated calls an unattended turn denied fail-closed (#623), accumulated across the loop iterations. Each entry is a call the capability gate would have escalated on a turn with RunTurnOptions::unattended set, where no live grant covered the shape; the model saw a legible denial result and the call neither ran nor paused. The final TurnResult::unattended_denials carries them out for the control plane to audit. Always empty on an attended turn.

§escape_hatch_fired: bool

Whether the fuzzy-match escape hatch (#582, invariant 9) has fired this turn. The hatch widens the advertised tool set at most ONCE per turn; once set, a later call naming an unadvertised tool resolves to the ordinary unknown-tool result again.

§delegate_records: Vec<DelegateRecord>

One entry per __delegate_to call dispatched this turn (#872), accumulated across the loop iterations. The final TurnResult::delegate_records carries them out for the control plane to append as signed forensic events. Empty for every turn that never called __delegate_to.

Implementations§

Source§

impl<P, T> TurnCtx<'_, P, T>
where P: LlmProvider + ?Sized, T: ToolExecutor + ?Sized,

Source

pub fn finish( self, pending_approvals: Vec<PendingApproval>, handoff: Option<HandoffRequest>, ) -> TurnResult

Consumes the turn’s working state into a crate::TurnResult, moving every accumulated audit surface out in one place.

The turn loop’s return sites differ only in the approvals they surface and whether a handoff rides along; the transcript, folded usage, last stop reason, and the audit surfaces (#594 grant replays, #623 unattended denials) are always whatever the context accumulated. Owning that move here makes forgetting an audit surface at a return site impossible by construction.

Source

pub fn finish_failed(self, failure: MidStreamFailure) -> TurnResult

Consumes the turn’s working state into a crate::TurnResult that reports a mid-turn provider stream failure (#798), exactly like Self::finish but with crate::TurnResult::mid_stream_failure set and no pending approvals (a failed stream never paused for HITL).

Whatever the loop already accumulated — executed tool results, produced text, folded usage — rides along on the returned crate::TurnResult instead of being discarded, which is the whole point: the caller can persist iterations 1..N-1’s work AND fail the turn with a typed error, rather than losing both to a bare Err propagated via ?.

Auto Trait Implementations§

§

impl<'a, P, T> !RefUnwindSafe for TurnCtx<'a, P, T>

§

impl<'a, P, T> !UnwindSafe for TurnCtx<'a, P, T>

§

impl<'a, P, T> Freeze for TurnCtx<'a, P, T>
where P: ?Sized, T: ?Sized,

§

impl<'a, P, T> Send for TurnCtx<'a, P, T>
where P: ?Sized, T: ?Sized,

§

impl<'a, P, T> Sync for TurnCtx<'a, P, T>
where P: ?Sized, T: ?Sized,

§

impl<'a, P, T> Unpin for TurnCtx<'a, P, T>
where P: ?Sized, T: ?Sized,

§

impl<'a, P, T> UnsafeUnpin for TurnCtx<'a, P, T>
where P: ?Sized, T: ?Sized,

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> 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, 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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

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