pub struct ElicitStep {
pub kind: ElicitKind,
pub plugin_name: String,
pub channel: Option<String>,
pub from: String,
pub purpose: Option<String>,
pub scope: Option<String>,
pub timeout: Option<String>,
pub config_override: Option<Value>,
pub on_error: Option<String>,
pub source: String,
}Expand description
One elicitation invocation inside policy: or post_policy: — the
runtime dispatches a question to a human (approval, confirmation,
step-up, …) through a channel plugin, holds a pending state across
the agent’s retries, validates the response, and resumes.
Structurally the elicitation analogue of DelegateStep: the DSL
carries the verb; apl-cpex dispatches resolution to the named
ElicitationHandler plugin (plugin_name, resolved exactly like
delegate(...)). The key
difference from delegation — which completes within one request — is
that an elicitation spans the gap between dispatch (the first
request that hits this step) and resolution (a later retry). That
gap is owned by the channel (e.g. Keycloak CIBA), never by a plugin
call: each of dispatch/check/validate is short and synchronous to the
request it runs in. See docs/apl-manager-approval-ciba-design.md.
§First arrival vs. retry
On the first request that reaches this step, the runtime dispatches
the elicitation and the phase yields a pending entry (the host emits
JSON-RPC -32120). On a later retry carrying the elicitation id, the
runtime checks status and, once resolved, validates the response
against scope before the phase may proceed.
config_override is a free-form map for channel-specific params
(e.g. CIBA details_link, Slack block-kit options); apl-core treats
it as opaque and hands it to the plugin via the same per-call
config-override pathway delegation uses.
Fields§
§kind: ElicitKindWhich elicitation contract applies (selects runtime validation).
plugin_name: StringName of the ElicitationHandler plugin to invoke — the routing
key, resolved name → entry exactly like delegate(...) resolves
its plugin. The first positional argument of the sugar verb (e.g.
require_approval(manager-approver, ...)). Which backend it speaks
(CIBA / Slack / in-band) is the plugin’s own opaque config, not
something apl-core interprets.
channel: Option<String>Optional channel label for audit/observability only (e.g.
"ciba", "slack"). NOT a routing key — the framework never
dispatches on it. Surfaced into the bag as elicitation.channel
so the audit record can show how the human was reached. None
when the author doesn’t declare one (a Phase 2 plugin may report
its own channel instead).
from: StringWho is being asked — an attribute reference resolved against the
policy bag at dispatch (e.g. "user.manager", "user.sub"). For
CIBA this becomes login_hint; the resolved identity is
cross-checked against the responder at validate().
purpose: Option<String>Canonical, human-readable description of what’s being asked, with
request-arg substitution. Audited verbatim and shown to the
responder (CIBA binding_message) — the source of truth for
“what was approved,” never an LLM summary. None for kinds that
carry their prompt elsewhere.
scope: Option<String>APL boolean expression the runtime evaluates against the actual
request args at validate() to confirm the response covers what
was requested (e.g. "args.amount <= 25000"). This is the
args-binding layer — kept in APL because Keycloak does not support
RFC 9396 RAR. None for kinds without arg binding (e.g. a bare
confirm).
timeout: Option<String>How long the elicitation stays valid before expiring (e.g.
"24h"). Surfaces as CIBA requested_expiry. None defers to
the channel plugin’s configured default.
config_override: Option<Value>Per-call config overrides for channel-specific params, layered on the plugin’s default config. Opaque to apl-core.
on_error: Option<String>deny | continue — what to do when dispatch or validation fails
(channel error, invalid response). None defaults to "deny"
(fail-closed; matches delegation/PDP step semantics).
source: StringHuman-readable source path (e.g.
"route.payroll_adjust.policy[0]") — used in audit and
Decision::Deny.rule_source when the step denies.
Trait Implementations§
Source§impl Clone for ElicitStep
impl Clone for ElicitStep
Source§fn clone(&self) -> ElicitStep
fn clone(&self) -> ElicitStep
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more