pub struct ApprovalDialer { /* private fields */ }Expand description
Reusable handle for the control plane’s ApprovalService.
The THIN human-in-the-loop path. Shares the AgentService endpoint — both
are served on one Connect port — so it is built from the same address.
Implementations§
Source§impl ApprovalDialer
impl ApprovalDialer
Sourcepub fn new(addr: &str) -> Result<Self, DialError>
pub fn new(addr: &str) -> Result<Self, DialError>
Build a dialer pointed at addr (expects http://host:port).
§Errors
Returns DialError::InvalidAddress if addr isn’t a valid URI.
Sourcepub fn with_bearer(addr: &str, bearer: &str) -> Result<Self, DialError>
pub fn with_bearer(addr: &str, bearer: &str) -> Result<Self, DialError>
Build a dialer pointed at addr, authenticated with bearer.
Every call this dialer makes carries an Authorization: Bearer <bearer> header. ApprovalService doesn’t send AgentStart, so no
signed AssertedAttribution envelope rides these calls — bearer-only.
A bearer alone cannot assert who resolved an approval; a dialer that
also holds its edge’s signing key uses Self::with_credentials.
§Errors
Returns DialError::InvalidAddress if addr isn’t a valid URI, or
DialError::InvalidBearer if bearer can’t be encoded as an HTTP
header value.
Sourcepub fn with_credentials(
addr: &str,
credentials: Arc<EdgeCredentials>,
) -> Result<Self, DialError>
pub fn with_credentials( addr: &str, credentials: Arc<EdgeCredentials>, ) -> Result<Self, DialError>
Build a dialer pointed at addr, authenticated with credentials.
Rides credentials.bearer() as the Authorization header, exactly
like Self::with_bearer, and additionally signs an
AssertedApproval onto every Self::respond that names a responder
(#1553) — one implementation every edge inherits, rather than one
per surface.
Takes an Arc because these are the SAME credentials the edge’s
AgentDialer holds: one edge, one identity key, whether it is
dispatching a turn or asserting who approved one.
AgentDialer::approval_dialer_with_credentials is the usual way to
build this.
§Errors
Returns DialError::InvalidAddress if addr isn’t a valid URI, or
DialError::InvalidBearer if the bearer can’t be encoded as an HTTP
header value.
Sourcepub async fn respond(
&self,
turn_id: &str,
request_id: &str,
choice: ApprovalChoice,
reason: &str,
conversation_id: &str,
modified_args_json: &str,
injected_context: &str,
resolve_token: &str,
responder: Option<ExternalIdentity>,
) -> Result<ApprovalOutcome, DialError>
pub async fn respond( &self, turn_id: &str, request_id: &str, choice: ApprovalChoice, reason: &str, conversation_id: &str, modified_args_json: &str, injected_context: &str, resolve_token: &str, responder: Option<ExternalIdentity>, ) -> Result<ApprovalOutcome, DialError>
Submit a human’s decision for a pending approval. The decision is
UNSIGNED — the control plane signs and persists it (THIN path) and
returns the signature. Idempotent: answering an already-decided or
unknown (turn_id, request_id) occurrence returns persisted: false.
When approved_for_session is true (and approved is true), the
control plane remembers the decision for the paused turn’s caller and
auto-approves that caller’s later identical, idempotent tool calls for
the rest of the session (“approve & don’t ask again”). Ignored on a
denial.
When abort is true (only meaningful with approved = false), this is
an abort: the call is declined AND the caller should stop the turn (not
re-drive it). A plain denial (approved = false, abort = false)
declines the call but lets the turn continue. See ApprovalChoice,
which maps a button decision to these flags.
resolve_token is the short-lived signed capability (#787) carried
unmodified off the TurnEvent::ApprovalPending event or
PendingApproval entry this decision answers — required: the
control plane rejects a Respond whose token is missing, expired, or
bound to a different turn, request, or conversation.
responder is the identity of the human answering (#68), as this
edge’s own provider verified it. A dialer built by
Self::with_credentials signs it into the request as an
AssertedApproval (#1553); the control plane enforces a turn’s
required approver (IngressDirective.required_approver) against the
verified identity alone, so Approve of such a turn is refused unless
the assertion verifies AND matches.
Asserting nothing is a supported state, not an error: an edge that
cannot attribute the responder passes None, a machine decision
carries none, and a dialer without credentials has no key to sign one
with. Deny and Defer are unaffected either way — refusing is safe
regardless of who refuses — and so is Approve of a turn that names no
required approver.
§Errors
Returns DialError::Connect for any transport/encoding error
(including the control plane’s rejection of an invalid
resolve_token, or a permission_denied when the verified responder
doesn’t match the turn’s required approver).
Sourcepub async fn list_pending(
&self,
conversation_id: &str,
) -> Result<Vec<PendingApproval>, DialError>
pub async fn list_pending( &self, conversation_id: &str, ) -> Result<Vec<PendingApproval>, DialError>
List the conversation’s outstanding approvals (a request with no later
response). An edge calls this to recover request_id(s) it must prompt
on after losing the streamed ApprovalPending event — turning a silent
hang into a recoverable state. Read-only and idempotent.
§Errors
Returns DialError::Connect for any transport/encoding error.
Sourcepub async fn list_recovery(
&self,
conversation_id: &str,
) -> Result<Vec<RecoverableApproval>, DialError>
pub async fn list_recovery( &self, conversation_id: &str, ) -> Result<Vec<RecoverableApproval>, DialError>
List saved approval decisions that need their paused turn resumed.
Unlike Self::list_pending, these entries intentionally carry no
resolve capability: a decision has already been recorded, or the
control plane must re-prompt it durably. A malformed repeated page token
is refused rather than allowing a caller’s recovery loop to spin.
§Errors
Returns DialError::Connect for transport failures and
DialError::InvalidApprovalRecovery when pagination repeats a token.
Sourcepub async fn excise_taint(
&self,
conversation_id: &str,
positions: &[u64],
all_quarantined: bool,
source_only: bool,
reason: &str,
actor: ExternalIdentity,
) -> Result<ExcisionOutcome, DialError>
pub async fn excise_taint( &self, conversation_id: &str, positions: &[u64], all_quarantined: bool, source_only: bool, reason: &str, actor: ExternalIdentity, ) -> Result<ExcisionOutcome, DialError>
Remove outside content from a conversation (#590) so its web and
outside access recover. Admin-gated server-side; the control plane
verifies actor holds the admin role, appends the signed removal
record, and reports which journal positions left the working context.
positions names specific entries; all_quarantined removes every
entry currently carrying outside content (positions is then
ignored). source_only limits the removal to the named entries — the
default also removes what the agent produced after them, which is the
safer posture when the content may have steered it.
§Errors
Returns DialError::Connect for any transport/encoding error, a
permission refusal, or an invalid position.
Sourcepub async fn replay_conversation(
&self,
conversation_id: &str,
from: Option<usize>,
to: Option<usize>,
over: Option<ReplayOverrideSpec>,
actor: ExternalIdentity,
) -> Result<ReplayReport, DialError>
pub async fn replay_conversation( &self, conversation_id: &str, from: Option<usize>, to: Option<usize>, over: Option<ReplayOverrideSpec>, actor: ExternalIdentity, ) -> Result<ReplayReport, DialError>
Replay a recorded conversation against its committed event log (#690):
re-execute its committed turns in process — no live model, no live tools,
nothing sent or spent again — and return a per-turn verdict. Read-only:
the control plane appends nothing and takes no writer lease, so it is safe
to run on production data any number of times.
Admin-gated (#694): the control plane verifies actor holds the admin
role — the same gate excise_taint applies — before it reads or replays
anything, so a non-admin (or absent) actor is refused.
from/to bound the 0-based committed-turn ordinals (inclusive); None
means the ends. A set over selects what-if mode (fork one recorded step
and report where the conversation diverges); None is a plain verify
(assert every turn reproduces its record).
§Errors
Returns DialError::Connect for any transport/encoding error, or a
permission refusal when actor is not an admin.
Sourcepub async fn verify_conversation(
&self,
conversation_id: &str,
actor: ExternalIdentity,
) -> Result<VerificationOutcome, DialError>
pub async fn verify_conversation( &self, conversation_id: &str, actor: ExternalIdentity, ) -> Result<VerificationOutcome, DialError>
Verify a conversation’s tamper-evidence (#799): replay its event log
and check every signed MMR root recorded along the way against a
freshly rebuilt tree. Read-only — appends nothing.
Admin-gated server-side, the same gate excise_taint uses.
§Errors
Returns DialError::Connect for any transport/encoding error, or a
permission refusal when actor is not an admin.
Sourcepub async fn repair_conversation(
&self,
conversation_id: &str,
actor: ExternalIdentity,
operation_id: &str,
) -> Result<Vec<u64>, DialError>
pub async fn repair_conversation( &self, conversation_id: &str, actor: ExternalIdentity, operation_id: &str, ) -> Result<Vec<u64>, DialError>
Repair a conversation’s event log (#799, the conversation repair
quarantine verb): replay every position independently so one
corrupted item cannot block the rest, then rewrite the partition
retaining only what decoded. A partition with nothing corrupted is a
no-op (empty quarantine list).
Admin-gated server-side, the same gate excise_taint uses.
§Errors
Returns DialError::Connect for any transport/encoding error, or a
permission refusal when actor is not an admin.
Trait Implementations§
Source§impl Clone for ApprovalDialer
impl Clone for ApprovalDialer
Source§fn clone(&self) -> ApprovalDialer
fn clone(&self) -> ApprovalDialer
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for ApprovalDialer
impl !UnwindSafe for ApprovalDialer
impl Freeze for ApprovalDialer
impl Send for ApprovalDialer
impl Sync for ApprovalDialer
impl Unpin for ApprovalDialer
impl UnsafeUnpin for ApprovalDialer
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> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
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 moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request