pub struct ResumePrePass<'a> {
pub tool_specs: &'a [ToolSpec],
pub approved_overrides: &'a HashMap<(String, String, String), ApprovalOverride>,
pub denied_call_ids: &'a HashSet<(String, String, String)>,
}Expand description
The approval resume pre-pass: resolve the tool calls a human already decided.
Before the turn drives the model, execute the calls the human approved that are dangling in the resumed transcript, resolve signed or denied calls to synthetic results, splice those results in after the paused batch, and append any approver-injected context notes.
On an approval resume the control plane replays the paused turn’s assistant
tool_use (which has NO paired tool_result — the call was paused, never
executed) and forwards the signed decisions via
RunTurnOptions::approved_call_ids / RunTurnOptions::denied_call_ids.
The function-calling loop only executes tool calls the model emits this
turn, so without this step an approval takes effect only if the model
happens to RE-EMIT the same call. Resolving the dangling calls
deterministically here makes an approval ALWAYS take effect, independent of
whether the model re-emits.
Classification and the #141 approval binding mirror the in-loop batch so the two can’t drift. It runs only on a resume: a fresh turn carries an empty decision set, so this step is a no-op and the hot path is unchanged.
A forwarded signed decision must never resolve silently to nothing: whenever
approved_call_ids is non-empty, Self::run logs a resolution summary and
tracing::warn!s individually for every approved tuple that matches no
unanswered call in the resumed transcript — distinguishing an already-
answered (harmless) re-forward from a call that is missing outright (a
projection loss upstream, e.g. one folded into a compaction summary). This
is purely observational: an approval that resolves to nothing still resolves
to nothing (re-pausing here would loop), but the loss is now loud instead of
surfacing only as an unexplained model refusal downstream.
Borrows the turn’s read-only resume inputs — the pinned tool-spec set (for
pause-card titles), the approver edits, and the signed denials — while the
mutable working state (transcript, outputs, the sticky denial set, and the
remaining approvals) rides the TurnCtx.
Fields§
§tool_specs: &'a [ToolSpec]The turn’s pinned tool-spec set, read once for pause-card titles.
approved_overrides: &'a HashMap<(String, String, String), ApprovalOverride>Approver edits (#67), keyed by the canonicalized approval identity.
denied_call_ids: &'a HashSet<(String, String, String)>Verified signed denials as canonicalized (id, name, args) tuples.
Trait Implementations§
Source§impl<P, T> TurnStep<P, T> for ResumePrePass<'_>
impl<P, T> TurnStep<P, T> for ResumePrePass<'_>
Source§fn run<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 mut TurnCtx<'life2, P, T>,
) -> Pin<Box<dyn Future<Output = Result<StepOutcome, P::Error>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn run<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 mut TurnCtx<'life2, P, T>,
) -> Pin<Box<dyn Future<Output = Result<StepOutcome, P::Error>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Auto Trait Implementations§
impl<'a> Freeze for ResumePrePass<'a>
impl<'a> RefUnwindSafe for ResumePrePass<'a>
impl<'a> Send for ResumePrePass<'a>
impl<'a> Sync for ResumePrePass<'a>
impl<'a> Unpin for ResumePrePass<'a>
impl<'a> UnsafeUnpin for ResumePrePass<'a>
impl<'a> UnwindSafe for ResumePrePass<'a>
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> 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