Skip to content

Human in the Loop

Fontana treats human approval as a first-class control. Agents can analyse, draft, and propose, but consequential changes are not applied until approved. Chat threads pause on structured prompts, canvas edits require an explicit apply step, and natural-language operation compiles stay pending until you confirm. Every path leaves audit metadata you can review alongside Compliance evidence.

Suggestions

Surface workflow suggestions in-thread so reviewers can accept or reject proposed changes without leaving the audit trail.

Human In the Loop Form

Collect questionnaires, clarifications, and approvals as structured forms embedded directly in the agent thread.

Not every AI step needs a human click. Fontana separates assist work (safe to run automatically under your agent and RBAC settings) from approval-gated work (changes that affect production rules, outputs, or control policies).

Agents can assist automatically Tasks that require your approval
Analyse files, schemas, and source outputs Change production rules or workflow boundaries
Infer fields, mappings, and validation checks for review Approve exceptions, outputs, or control changes
Draft operating specifications and mapping proposals Execute operational steps in production
Explain breaks, exceptions, and supporting evidence Bypass prompt, output, routing, version, and decision logs
Propose workflow configuration before it is applied Override named owners, approval gates, or control policies
Summarise evidence packs for reviewers Act outside defined permissions and data-class boundaries

Your Agents allowlist, Roles and RBAC, and each agent’s tool assignments further narrow what server-side tools can run without an explicit human step.

The askHuman tool (structured chat prompts)

Section titled “The askHuman tool (structured chat prompts)”

The primary chat HITL mechanism is the built-in askHuman tool (catalog id chat_askHuman). Agents call it whenever they need a question, confirmation, or choice from you. The model must use the tool rather than relying on plain-text questions alone, so the thread pauses until you submit an answer and the UI always renders a governed form.

Input shape:

Field Required Purpose
schema Yes JSON Schema object describing fields, types, validation, and question copy (title, description)
uiSchema No Optional UI hints (widgets, layout) compatible with react-jsonschema-form conventions
actions No Named buttons that replace the default Submit control. Each item is { id, label, color? }. Colour is one of gray, blue, sky, teal, green, amber, red, violet. Omit or pass [] for Submit plus Cancel. Include id: "cancel" to set Cancel’s label and colour.

Every pending form shows Cancel. Cancel submits { "action": "cancel", "values": null } without validating the fields. Per-tool Stop in the chat transcript is a separate control.

Flow in-app only: hitl_askHuman (catalog hitl_askHuman) completes in the Flow supplementary drawer only.

Slack Chat Channels: agents call hitl_slackBlocks with Block Kit (and optional Slack modals). On a Slack-bound thread, omit destination args — the card posts in that thread. From Flow chat, pass installationId (Chat Channels Slack installation) and channel (Slack channel id) to post a gated approval card to an ops channel; any linked Slack user may click Approve/Reject. Clicks return the same { action, values } envelope. hitl_askHuman completes in Flow only. Microsoft Teams still opens Flow.

Response: a stringified JSON object { "action": "<button id>", "values": <form data or null> }. Default Submit uses "action": "submit". The agent reads action to branch (for example Send Now vs Save Draft) and values for the field data. The turn continues after you click a button.

Flow renders the form in the chat supplementary drawer (HITL slot). When multiple askHuman calls are pending, you page through them one at a time. Submitting an answer calls submitToolResult, which persists the result and schedules the next model turn.

Supported leaf types include boolean, string (including format hints such as date, date-time, email, and uri), number/integer (including ui:widget: "range" on either), enum (with or without an explicit type), array, and object. Optional uiSchema widgets include textarea, password, range, radio, select (Flow DropdownSelect, not a native <select>), and ui:readonly. const fields render locked to that value.

A property whose own type is object with fixed properties renders as its own labelled group of sub-fields (recursively, to any depth) rather than a raw JSON editor; only a free-form object with no fixed properties (additionalProperties only) falls back to a JSON editor, since dynamic keys have no fixed field list to render.

Arrays:

items shape What you see
Enum of scalars Checkbox multi-select
Homogeneous string (no enum) Add / remove text rows
Object with fixed properties Add / remove structured cards
Tuple (items is an array of schemas) One control per position
Other item shapes JSON editor fallback

Nested objects and arrays use a semi-transparent background wash under their parent label (no nested borders). Stacked nests read darker in light mode and lighter in dark mode. Long forms scroll inside the chat supplementary drawer. If a leaf uses an unsupported or unknown type, Flow still renders an editable text input so required fields remain fillable; the submitted value for that leaf is the typed string.

Boolean approval:

{
"type": "object",
"properties": {
"approved": {
"type": "boolean",
"title": "Approve this change?",
"description": "Do you want to proceed with this modification?"
}
},
"required": ["approved"]
}

Named form buttons: pass actions on the tool call (not inside the JSON Schema or uiSchema). Result is { "action": "send_now", "values": { "body": "…" } } or { "action": "cancel", "values": null }.

{
"schema": {
"type": "object",
"properties": {
"body": {
"type": "string",
"title": "Message"
}
},
"required": ["body"]
},
"actions": [
{ "id": "send_now", "label": "Send Now", "color": "teal" },
{ "id": "save_draft", "label": "Save Draft" }
]
}

Single select: renders as buttons by default, or a dropdown via uiSchema: { "ui:widget": "select" }.

{
"type": "object",
"properties": {
"priority": {
"type": "string",
"enum": ["low", "medium", "high"],
"title": "Priority level"
}
},
"required": ["priority"]
}

Multi-select checkboxes: an array of an enum always renders as a checkbox list (no uiSchema needed):

{
"type": "object",
"properties": {
"categories": {
"type": "array",
"items": {
"type": "string",
"enum": ["urgent", "important", "optional"]
},
"title": "Select categories"
}
}
}

Number slider:

{
"type": "object",
"properties": {
"threshold": {
"type": "number",
"minimum": 0,
"maximum": 100,
"title": "Threshold"
}
},
"uiSchema": {
"threshold": { "ui:widget": "range" }
}
}

Multiple fields in one prompt: use an object schema with several properties, including nested object properties for grouped sub-fields. Boolean and single-select fields can render as one-click controls when they are the only field in the form.

Assign chat_askHuman to agents in Admin → Agents like any other built-in tool. See Tools and MCP for the wider tool catalog.

hitl_askHuman is a deferred tool with no server-side executor — it waits for completion in Flow. hitl_slackBlocks is also deferred but posts Block Kit to the Slack thread and waits for Bolt interactivity there.

Model turn completes → tool call persisted (pending)
↓
Flow detects pending askHuman → renders form (CITL)
↓
You submit → submitToolResult → tool result persisted
↓
Thread schedules next model turn

Client In The Loop (CITL) orchestration applies only to askHuman / chat_askHuman. All other agent tools (workflow queries, canvas mutations, Knowledge Graph search, MCP calls) execute server-side after the same deferred pipeline, subject to the agent’s tool allow-list. Workflow discovery on each prompt is the agent’s autoSearchWorkflows frontmatter setting, not a chat toggle.

One active browser tab holds the CITL lease per conversation root so duplicate submissions do not race. While a prompt is open, the thread run status shows that the agent is waiting for you, not still analysing.

The Canvas agent mutates a draft workflow graph stored per chat thread (ai_thread_canvas), not your saved workflow directly. When the agent finishes a batch of edits, Flow shows a suggestion card comparing the draft to your baseline. Nothing is written to the live canvas until you click Apply.

Step What happens
Agent edits Typed canvas tools update server-side aiConfig on the thread canvas row
Review getCanvasSuggestions returns a structured diff in the chat or canvas panel
Apply applyCanvasSuggestions promotes the draft, with three-way merge if you edited locally since the thread started
Conflict If agent and live edits overlap, you choose merge resolution or overwrite via an explicit modal

Auto-apply is opt in (user preference, default off). Production canvas changes always go through the same apply mutation when auto-apply is disabled.

Natural-language Operations compile review

Section titled “Natural-language Operations compile review”

On Operations nodes, plain-English rules compile through the NL Operation Compiler agent. Successful compiles land in a pending card (dashed border) until you:

  • Confirm - merge (possibly edited) operations into the node
  • Rephrase - send the description back to the composer for another compile attempt
  • Reject - discard the proposal

Policy validation and automatic repair retries run in Convex; you always see the final proposal before it affects workflow execution. Confirmed operations collapse in the editor; the composer is disabled while a pending card is visible.

Human-in-the-loop checkpoints stack with other AI controls:

Layer How it gates AI work
Tool allowlist Unassigned tools (built-in or MCP) are not callable
RBAC Flow hides admin and mutation surfaces when your role lacks permission
Thread toggles Disable data or config sharing to block query tools until you re-enable via askHuman
Deferred tools hitl_askHuman in Flow; hitl_slackBlocks on Slack; Cancel is not Stop
Suggestion apply Canvas drafts never replace saved workflows silently
NL compile HITL Operations are not persisted until Confirm
Audit trail Tool calls, submissions, and apply actions write reviewable records

For immutable security audit and operational telemetry boundaries, see Security audit (WORM) and Compliance evidence.

  • Agents - configure which personas may call askHuman and other tools
  • Tools and MCP - built-in catalog, MCP allowlists, and audit
  • Skills - temporary tool expansion during governed playbooks
  • Workflows - Operations nodes and NL compile behaviour