Skip to content

docs: Document Aura HITL webhook header forwarding and tool_call_intent - #90

Open
promptless[bot] wants to merge 2 commits into
mainfrom
promptless/aura-hitl-forwarding
Open

docs: Document Aura HITL webhook header forwarding and tool_call_intent#90
promptless[bot] wants to merge 2 commits into
mainfrom
promptless/aura-hitl-forwarding

Conversation

@promptless

@promptless promptless Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Open in Promptless

Two merged Aura pull requests extended the human-in-the-loop (HITL) approval webhook, and the docs did not yet cover either change. This suggestion documents both on the Aura HITL page and configuration reference.

  • Webhook header forwarding (mezmo/aura #490): documents the two new optional [hitl.route] keys available in webhook mode — headers (static outgoing headers, supporting {{ env.VAR }} interpolation) and headers_from_request (forward a header from the incoming API request onto the approval POST). Covers precedence, case-insensitive lookup, lowercased outgoing names, the CLI-standalone (AURA_EXTRA_HEADERS) behavior, and a security warning about forwarding sensitive headers such as authorization.
  • tool_call_intent (mezmo/aura #489): documents the new optional field in the webhook payload's items[] — the agent's rationale for a gated tool call, shown to the human approver. Notes that it is agent-generated (treat as untrusted), omitted entirely when absent, does not change the protocol version, and appears only in the webhook payload (not the SSE approval events or the conversational route).

Files touched: aura/hitl.mdx, aura/configuration-reference.mdx, and vale/styles/config/vocabularies/Mintlify/accept.txt (adds untrusted).

Trigger Events


Tip: Sort by Shortest Review in the Dashboard to find quick wins ⚡

Document two merged Aura HITL enhancements on the approval webhook:
- headers / headers_from_request on [hitl.route] (webhook mode) for
  attaching static and request-forwarded headers to the approval POST
- the optional tool_call_intent field in the webhook items[] payload

Adds a security warning about forwarding sensitive headers, a config
reference entry, and 'untrusted' to the Vale accept vocabulary.

Relates to: mezmo/aura#490, mezmo/aura#489
Comment thread aura/hitl.mdx

- `tool_name` — the gated MCP tool being called.
- `arguments` — the tool call arguments.
- `tool_call_intent` — **Optional.** A short natural-language rationale the agent

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ApprovalItem.tool_call_intent is Option<String> with #[serde(default, skip_serializing_if = "Option::is_none")] — confirms it is optional and omitted (not null/empty) when absent.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura/src/hitl/protocol.rs#L46-L52

Comment thread aura/hitl.mdx
untrusted and escape or sanitize it like any other model output.
- Omitted entirely from the payload (not `null`, not an empty string) when the
agent supplies no rationale, so its absence does not change the protocol
`version`.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PROTOCOL_VERSION const = 1, unchanged by the new optional field — confirms "does not change the protocol version" claim.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura/src/hitl/protocol.rs#L11

@mintlify

mintlify Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
mezmo-docs 🟢 Ready View Preview Aug 18, 2026, 5:01 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Comment thread aura/hitl.mdx
Aura does not act on it automatically. Because it is agent-generated free text,
a webhook receiver that displays it to a human approver should treat it as
untrusted and escape or sanitize it like any other model output.
- Omitted entirely from the payload (not `null`, not an empty string) when the

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non_blank() collapses empty/whitespace-only agent reasoning to None, so blank rationale never appears on the wire as an empty string.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura/src/tool_wrapper.rs#L109-L112

Comment thread aura/hitl.mdx
agent supplies no rationale, so its absence does not change the protocol
`version`.

`tool_call_intent` appears only in the webhook payload's `items[]`. It is not

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ApprovalRequested, ApprovalPending, and ApprovalCompleted SSE DTOs have no tool_call_intent field — confirms it appears only in the webhook items[] payload, not the SSE events or conversational pending prompt.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura-events/src/lib.rs#L883-L912

Comment thread aura/hitl.mdx
@@ -196,6 +259,9 @@ posting a decision. `aura.approval_completed` includes `decision_id`, terminal
`timed_out`, `cancelled`, and `errored`; `errored` means the approval channel
failed before a human decision was obtained.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same SSE DTOs (ApprovalRequested/Pending/Completed) confirm the lifecycle events do not carry tool_call_intent.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura-events/src/lib.rs#L883-L912

Comment thread aura/hitl.mdx

## Forward headers to the webhook

The webhook route accepts two optional `[hitl.route]` keys (valid only when

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DecisionRouteConfig::Webhook variant adds optional headers and headers_from_request fields (#[serde(default)]), valid only for mode = "webhook".

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura-config/src/config.rs#L1150-L1160

Comment thread aura/hitl.mdx

- `headers` — a static map; values are sent verbatim on every approval POST.
- `headers_from_request` — maps **outgoing header name → incoming request header
name**; the incoming lookup is case-insensitive.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apply_request_header_mappings does a case-insensitive (.to_lowercase()) lookup of the mapped incoming request header name.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura/src/rig_builder.rs#L172-L190

Comment thread aura/hitl.mdx
- `headers` — a static map; values are sent verbatim on every approval POST.
- `headers_from_request` — maps **outgoing header name → incoming request header
name**; the incoming lookup is case-insensitive.
- Precedence: when the mapped incoming request header is present, the forwarded

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolve_webhook_headers overlays apply_request_header_mappings results onto the lowercased static headers map, so a present mapped request header overrides the matching static value; absent request header leaves the static value as fallback.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura/src/hitl/route.rs#L207-L226

Comment thread aura/hitl.mdx
value overrides any static `headers` value for the same (case-normalized) name.
- When the incoming header is absent, the static `headers` value remains as a
fallback.
- Aura sends all resolved outgoing header names in lowercase.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static header keys are lowercased and apply_request_header_mappings inserts forwarded values under a lowercased outbound key, so all resolved outgoing header names are lowercase.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura/src/hitl/route.rs#L215-L223

Comment thread aura/hitl.mdx
fallback.
- Aura sends all resolved outgoing header names in lowercase.
- Both keys are optional; when both are absent, the approval POST is unchanged.
- Invalid header names or values are skipped with a warning and never abort the

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid HeaderName/HeaderValue conversions are skipped with tracing::warn! and never abort the request; the invalid value itself is never logged (only the key name).

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura/src/hitl/route.rs#L228-L245

Comment thread aura/hitl.mdx
mode = "webhook"
url = "https://approvals.example.com/aura"
timeout_secs = 300
headers = { "Authorization" = "Bearer {{ env.APPROVAL_WEBHOOK_TOKEN }}" }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolve_env_vars runs a whole-file regex substitution pass on the TOML text before parsing, so {{ env.VAR }} works in any string value, including [hitl.route].headers.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura-config/src/env.rs#L1-L20

Comment thread aura/hitl.mdx
url = "https://approvals.example.com/aura"
timeout_secs = 300
headers = { "Authorization" = "Bearer {{ env.APPROVAL_WEBHOOK_TOKEN }}" }
headers_from_request = { "x-request-id" = "x-request-id" }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parser test uses the identical inline-table TOML shape (headers = { "x-tenant" = "sre-prod" }) confirming the docs' example syntax parses correctly.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura-config/src/config.rs#L1070-L1085

| `mode` | string | — | **Required.** `"conversational"` (attended, over an open SSE stream) or `"webhook"` (unattended, posts to a URL). |
| `timeout_secs` | integer | `60` (conversational) / `300` (webhook) | Seconds to wait for a decision before failing closed. |
| `url` | string | — | **Required for `webhook` mode only.** Must start with `http://` or `https://`. |
| `headers` | table | `{}` | **Webhook mode only.** Static outgoing headers `{ "header-name" = "value" }` sent on every approval POST. |

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

headers/headers_from_request table fields on DecisionRouteConfig::Webhook, both #[serde(default)] (default {}), webhook-mode only.

Source: https://github.com/mezmo/aura/blob/77128e43508bf1f20aca9b7551fb671d783e7beb/crates/aura-config/src/config.rs#L1150-L1160

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants