Documentsagenta
Schema-Driven Elicitation
Schema-Driven Elicitation
Type
Topic
Status
Published
Created
Jul 8, 2026
Updated
Jul 8, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Schema-Driven Elicitation#

Overview#

Schema-driven elicitation is the mechanism by which agents pause a run and request typed user input via a flat JSON schema rendered as an inline Ant Design form inside the playground agent chat. It is the first of three planned "interaction kinds" on the client-tool registry seam , replacing ad-hoc hand-built widgets with a payload-driven approach.

Two Use Cases#

  1. Standalone elicitation — Any agent can call request_input at any point during a run to collect non-secret structured input before proceeding (e.g., selecting a support platform, choosing a polling interval).
  2. Agent onboarding clarification — The playground-native onboarding flow uses elicitation to let the setup agent issue clarifying request_input calls mid-run while wiring a new agent from a free-text description .

Wire Contract#

The tool is named request_input and is a reserved static-catalog client tool auto-embedded in every build kit — no SDK changes needed to use it .

Its input schema :

  • message (string, required) — one-to-two sentence context shown above the form
  • requestedSchema (object, required) — a flat JSON Schema: top-level primitive properties only (string, number, integer, boolean). Supports enum, title, default, and format hints.
  • No nested objects or arrays are allowed.
  • Never request secrets — use request_connection for credentials.

Supported format values:

  • date, date-timeDatePicker (with showTime for date-time)
  • email, uriInput with validation
  • multilineInput.TextArea (3 rows)

Format aliases that LLMs naturally emit are normalized: textarea/multi-line/long-textmultiline; datetimedate-time; urluri .

Response envelope:

  • accept{action: "accept", content: {...}, humanFriendlyMessage}
  • decline{action: "decline", humanFriendlyMessage}
  • cancel{action: "cancel"}

Dispatch Mechanism (render.kind)#

Because AI SDK v6 tool chunks are strict and drop inline fields, the render.kind hint cannot be embedded directly in the tool call. It travels as a sibling data-render stream part, merged into a per-message map by buildRenderMap .

Two-stage dispatch in the client-tool registry :

  1. Primary: match on render.kind = "elicitation" from the render map.
  2. Fallback: match on toolName.
  3. Default: if neither matches, auto-settle with "not handled by this client" to prevent hang.

The ElicitationWidget component handles rendering, validation, and settlement . The resume predicate in agentApprovalResume.ts also keys on render.kind to know when to auto-resume after settlement.

Cross-Turn Isolation#

The runner's client-tool output store is scoped to the current turn only (at or after the latest user message). This prevents a second identical request_input call in a later turn from being silently fulfilled by the first turn's answer — it pauses and shows a fresh form . Approvals remain full-history (grants are idempotent).

Part States and Replay#

Elicitation parts cycle through four replayable states (defined in elicitation.ts):

StateRendered as
pendingLive interactive form
submittedRead-only chip showing accepted values
declinedRead-only chip
cancelledRead-only chip
degradedUnsupported-payload error surface

Reload while pending → live form re-renders and still accepts. Reload after settlement → chip replays read-only .

Contract Pinning#

All contract logic lives in @agenta/shared: payload validator, action envelopes, part-state derivation, format mapping, and a secret-field denylist. Both vitest and pytest assert against shared golden fixtures at web/packages/agenta-shared/tests/fixtures/elicitation_*.json, preventing wire-dialect drift across languages .

Agent Onboarding Integration#

The playground-native onboarding (PR #5076) drives elicitation through the same request_input client tool. The useAgentOnboarding hook mints an ephemeral agent, commits it in-place via history.replaceState, and the setup agent can issue request_input calls mid-run to collect clarifying details (e.g., which support platform to watch, scheduling preferences) before finalizing the agent configuration .

Key Source Files#

FilePurpose
ElicitationWidget.tsxForm rendering, validation, settlement, chip replay
elicitation.tsShared contract: validator, envelopes, part-state derivation, format normalization
renderMap.tsBuilds per-message render.kind map from data-render stream parts
SchemaForm.tsxFormat-aware field renderer (opt-in via formats={true})
static_catalog.pyDefines the request_input tool in the static workflow catalog
responder.tsTurn-scoped client-tool output store (cross-turn isolation fix)
agentApprovalResume.tsResume predicate keyed on render.kind
decisions.mdLocked design decisions for interaction kinds

Design Decisions#

  • Closed component set — three interaction kinds (elicitation, display, config-card); no open-ended generative UI. Model-composed arbitrary UI is explicitly out of scope .
  • Secrets never on the chat wire — platform widgets post to the vault API directly; use request_connection for credentials .
  • render.kind is required — without it, a client tool settles but never auto-resumes .
  • Adding a new kind costs one registry entry plus a contract module — not a new frontend widget per tool .
Schema-Driven Elicitation | Dosu