pub struct RunTurnOptions {
pub approved_call_ids: HashSet<(String, String, String)>,
pub approved_overrides: HashMap<(String, String, String), ApprovalOverride>,
pub denied_call_ids: HashSet<(String, String, String)>,
pub stream_tx: Option<UnboundedSender<TurnStreamEvent>>,
pub web_search: bool,
pub session_approved_tools: HashMap<String, CapabilitySet>,
pub escalate_sandbox_denials: bool,
pub untrusted_context_seed: bool,
pub dispatch_recorder: Option<Arc<dyn DispatchRecorder>>,
pub cache_hint: CacheHint,
}Expand description
Options for a single run_turn invocation.
A small builder-style struct rather than a long parameter list — keeps the
hot-path call sites readable (RunTurnOptions::default()) and gives the
HITL-resume path a typed slot for the approved-call-ids set without adding
a third positional HashSet argument every existing caller would have to
thread through.
Fields§
§approved_call_ids: HashSet<(String, String, String)>Provider-assigned tool-call ids the caller has previously gathered
signed HITL approvals for. When ToolExecutor::needs_approval
returns true for a tool call, the loop checks this set: if the
call’s id is present, the tool executes as normal; if absent, the
loop pauses with a fresh PendingApproval as today.
Used by the control plane → harness resume cycle: the control plane
replays the conversation’s event log, collects every verified
approval_response that isn’t yet answered by a matching tool_result
message in the transcript, and passes the set here so the harness
re-drives the function-calling loop with the previously-paused tools
executed.
Each entry is the signed (request_id, tool_name, args_json) tuple — the
approval is bound to that exact call (#141), so a re-emitted same-id call
with different args/tool does NOT inherit the approval (it re-pauses).
approved_overrides: HashMap<(String, String, String), ApprovalOverride>Per approved call, the approver’s in-flight EDIT to apply on execution
(#67): the arguments to run in place of the model’s proposal. Keyed by
the same signed (request_id, tool_name, args_json) identity as
Self::approved_call_ids, where the tuple’s args_json is the model’s
PROPOSED args (the identity), and the ApprovalOverride carries the
approver’s replacement. A call approved without an edit has no entry here
— resolve_approved_call then runs the proposed args unchanged, so the
common approve path is untouched.
denied_call_ids: HashSet<(String, String, String)>Verified signed HITL denials as (request_id, tool_name, args_json)
tuples (a verified approval_response with approved == false).
A denial must RESOLVE the call, not leave it pending: when
ToolExecutor::needs_approval returns true for a call whose
(id, name, args) tuple is in this set, the loop emits a synthetic denial
tool_result (carrying {"approved":false,"error":"denied by human approver"}) WITHOUT executing the tool and WITHOUT re-pausing. As with
approvals the denial is bound to the exact call — the same id with
different args is a new request, not an inherited denial.
A call needing approval that is in neither Self::approved_call_ids
nor this set still pends as before.
stream_tx: Option<UnboundedSender<TurnStreamEvent>>When set, the turn loop forwards each TurnStreamEvent (text delta,
tool start) as it arrives, so a caller can stream partial output
mid-turn (the harness forwards these over its bidi stream → control
plane → Slack chat.appendStream). None keeps the buffered path:
the full TurnResult is always returned regardless.
web_search: boolWhen true, each request this turn sets CompletionRequest::web_search
so the provider offers the model public-web grounding (Vertex Gemini maps
it to the googleSearch tool). Only the answering loop sets this; the
summarizer and classifier build their own requests and never enable it.
session_approved_tools: HashMap<String, CapabilitySet>Session-scoped approvals (“approve & don’t ask again”), already
filtered to THIS turn’s caller by the control plane (the per-user
scope): tool name → the capability set the signed grant covered at
approval time (#595). A gated call to one of these tools
auto-executes WITHOUT pausing — REGARDLESS of its arguments — but only
when the grant’s covered set includes every capability the call is
currently missing AND ToolExecutor::cacheable_approval returns
true for the tool (the authoritative idempotency gate: a
non-idempotent tool can never be session-approved even if a stale
entry is present).
Scoped per-tool (not per-exact-args) because “don’t ask again” means “stop prompting me for this tool”; a model rarely repeats an identical call, so binding to exact args would make the grant near-useless. The covered-capability key keeps one convenience approval from silently widening: if the tool’s required set later grows, the old grant does not cover the new capability and the gate asks again.
Unlike Self::approved_call_ids these are NOT drained on execution.
escalate_sandbox_denials: boolEnable the graduated-approval sandbox-denial ESCALATION (#301): when
true, a call ToolExecutor::sandbox_would_deny flags is routed
through the approval gate (pauses with a PendingApproval) instead of
being executed and returning the sandbox’s flat denial to the model. The
control plane sets this from the resolved per-persona approval policy.
Default false, so existing callers are unaffected: a sandbox-denied
call runs and surfaces its own error exactly as before.
untrusted_context_seed: boolDurable seed for the untrusted-content-in-context taint state,
computed by the control plane over the conversation’s FULL durable event
log (any quarantined_content-tagged event) and OR-ed into the agent’s
structural in-memory check (untrusted_content_in_context). Taint is
the provenance input to grant derivation: while it holds, the granted
set loses arbitrary egress and external mutation.
The structural check only sees untrusted content that is still a live
LlmContent::ToolResult in the projected transcript. History compaction
folds older tool results into a single System summary message — erasing
the ToolResult the check keys on — and a non-principal participant’s
chat text is never a ToolResult at all. In both cases the durable log
still carries the quarantined provenance, so the control plane reads it
there and passes the verdict in here. true keeps the taint state live
even when the transcript looks clean; the containment escalation then
still fires.
Default false: a conversation with no durable untrusted provenance (and
no multi-party input) is unaffected, so a first egress on a genuinely
clean context still runs unattended.
dispatch_recorder: Option<Arc<dyn DispatchRecorder>>Signs + records dispatch mutations (#67, #539/#540) before they apply.
When None (the default), pre_dispatch Modify/InjectContext and
post_dispatch redactions are NOT applied — the proposed call runs and
the raw result stands — so a policy mutation is inert unless a signer is
wired. When present, each mutation is recorded first and applied only on
success (fail-closed).
cache_hint: CacheHintProvider prompt-caching hint for this turn (#629).
When CacheHint::StablePrefix, each step’s CompletionRequest marks
the stable prefix — the system text plus the tool-spec set built once per
turn (#628) — as cacheable, so a provider that supports prompt caching
skips re-processing it on every step (the biggest latency lever on a
multi-step turn). A provider without caching ignores it. Default
CacheHint::None ⇒ no caching, so auxiliary calls that build their own
options are unaffected. The control plane sets it from its turn-boundary
config snapshot, so the knob lands at a turn boundary, never as a compiled
constant.
Trait Implementations§
Source§impl Clone for RunTurnOptions
impl Clone for RunTurnOptions
Source§fn clone(&self) -> RunTurnOptions
fn clone(&self) -> RunTurnOptions
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for RunTurnOptions
impl Debug for RunTurnOptions
Source§impl Default for RunTurnOptions
impl Default for RunTurnOptions
Source§fn default() -> RunTurnOptions
fn default() -> RunTurnOptions
Auto Trait Implementations§
impl !RefUnwindSafe for RunTurnOptions
impl !UnwindSafe for RunTurnOptions
impl Freeze for RunTurnOptions
impl Send for RunTurnOptions
impl Sync for RunTurnOptions
impl Unpin for RunTurnOptions
impl UnsafeUnpin for RunTurnOptions
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> 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