You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Human-in-the-loop (HIL) elicitation for APL. A policy can pause an operation to ask a human — manager approval, a confirm, a step-up re-auth, an attestation — and resume once the human responds, without blocking the request path. Sugar verbs (require_approval / confirm / require_step_up / require_attestation / request_info / require_review) desugar to one Step::Elicit, resolved by name to an ElicitationHandler plugin exactly like delegate(...). While the human hasn't answered, the phase suspends (Decision stays Allow with a pending bundle) and the host emits JSON-RPC -32120 so the agent retries by echoing the elicitation id; expiry, channel error, denial, or a failed validation fail closed (default on_error: deny). The approval is bound to the live request args via an APL scope: expression (args.amount <= 25000) the runtime checks at resolution — never an LLM summary. Ships a working Keycloak CIBA channel plugin (kind: elicitation/ciba, in cpex-builtins default features). See [Elicitation]({{< relref "/docs/apl/elicitation" >}}). (#115)
Changed
read_headers granted to every synthetic policy handler. The entity-less HTTP catch-all, per-entity routes (tool/prompt/resource), and defaults are now all granted the read_headers capability at install time, so http.* request attributes (http.method / http.path / http.host / http.scheme / http.request_headers.*) are available to policy evaluation wherever the host attaches an HttpExtension. Previously only the global HTTP catch-all had it, so a per-entity rule could not read the HTTP request line. This lets one policy combine http.* with entity/args.* predicates in a single evaluation (e.g. an MCP tool route that also gates on http.method). It is a no-op for hosts that never populate the HTTP extension — there is nothing to read — and http.host continues to be sourced from a validated request authority, never a raw client Host header. (#120)
APL order comparisons now coerce numeric-looking strings.numeric_compare parses string operands as f64 for order operators (>, >=, <, <=), so args.amount > 10000 fires when the arg arrives as the string "25000" — as LLM tool arguments routinely do. This affects all order comparisons in the engine, not just elicitation scope: bindings: a comparison that previously returned false because one side was a numeric string may now evaluate numerically. Equality (==) is unchanged, and genuinely non-numeric strings still don't order-compare (they yield false, per spec §2.3). (#115)