Preferences Wizard

A step-by-step setup of the user's lasting preferences, with a review before saving.

Pattern

≈ 2,540 tokens per use (tool 1,782 · guidance 321 · typical payload 437)How token costs are estimated

Example: Preferences Wizard

Set up my news preferences

Set up your news preferences

For your morning digest and alerts.

Step 1 of 5: Topics

  1. Topics: current step
  2. Sources: not started
  3. Reading depth: not started
  4. Digest: not started
  5. Notifications: not started

0 selected · Pick at least 3

When to use

  • The user wants to set up or personalize lasting preferences the agent will use from now on: news topics, diet, travel style, notifications.
  • Onboarding, where a few visual choices replace a long back-and-forth.

When not to use

  • The agent needs answers for this one task only. Use a Question Stepper.
  • The user is booking, buying or submitting something. Use a Guided Flow.
  • The user wants to tune the constraints of an answer the agent already gave. Use Preference Controls.

How the agent should use it

  • Keep it to 2–8 short steps, broad to specific, each with a 1–3 word title.
  • Prefill value with the user's current settings when you know them; otherwise use sensible defaults. A skipped step keeps them.
  • Mark a step required only when you can't work without it. Everything else can be skipped.
  • Pick the input for the question: cards with icons for a handful of broad choices, chips for long or open lists, scale for a degree, rank for priorities, toggles for on/off settings, schedule for days and times.
  • Only save on save. Store answers as the user's settings, keep your defaults for the skipped steps, and say in one line what changes.
  • On dismiss, save nothing and don't ask again unless the user brings it up.
  • Lifecycle: no expiresAt or fetchedAt; preferences don't go stale. If the agent starts a new wizard for the same settings before this one is finished, mark the old call superseded (supersededBy).

Inputs

Every step has id, title, an optional description and required, and one input:

input.typeShowsAnswer
cardsA grid of cards with an icon or image and a check mark. One pick, or several with multiple (min, max)The option id, or an array of ids
chipsToggle chips, plus Add your own with allowCustomThe chosen chips, including the user's own
scaleThe current value, large, over a slider between two words, e.g. Headlines … Deep divesThe number
rankA list to reorder by drag or keyboardItem ids, most important first
togglesSwitches. An item's description is read to screen readers, not shown{ [itemId]: boolean }
scheduleWeekday chips and one time (from), or a range (from and to){ days, from, to? }, days 0 = Sunday … 6 = Saturday
textA short free-text answerThe trimmed text

Interaction

InputAction
NextDisabled until the step is valid: required, min and max picks, a day and a time for a schedule. An optional step with nothing picked and no min is a valid "none"
SkipShown when allowSkip is on and the step isn't required. The step keeps its default and is listed as "Using defaults"
BackPrevious step. Answers are kept
ReviewReplaces Next on the last step. The review lists every answer with an Edit button; editing returns to the review
Save preferencesSends save and leaves a compact record of the answers, marked "Saved to your profile"
Not nowSends dismiss. Nothing is saved
EnterIn a single-line input, continues. In Add your own, adds the chip
Space / arrowsIn a ranking: pick up, move, drop; Escape cancels. Each move is announced
  • Progress you can see. The header shows the icon, "Step 1 of 4" and the step title (with a quiet Required tag when it is), with a segmented bar, one segment per step, under it. Skipped steps are hollow, and the bar's screen reader text names each step as done, skipped, current or not started. For cards and chips with a limit, the footer tracks it on the left ("2 selected · Pick at least 3"), beside a quiet Not now; Back appears from step 2. Option cards show their check only once picked; photo cards are 4:3 with the label on the photo.
  • Focus follows the step. After moving, focus lands on the step heading, announced as "Step 2 of 5: Cuisines". Steps slide in their direction; with reduced motion they fade.
  • Streaming. The header arrives first, then the steps one by one. The user can start straight away; Next on the newest step waits until its options are complete, and the review waits for the whole payload.

Installation

npx shadcn@latest add https://your-site.com/r/preferences-wizard.json

Usage

app/api/chat/route.ts
import { tool } from "ai"
import { preferencesWizardTool } from "@/components/genui/preferences-wizard.schema"

const tools = {
  // No execute(): the call is completed by the user in the UI.
  [preferencesWizardTool.name]: tool({
    description: preferencesWizardTool.description,
    inputSchema: preferencesWizardTool.inputSchema,
  }),
}
components/message.tsx
import { PreferencesWizard } from "@/components/genui/preferences-wizard"

function ToolPart({ part, addToolResult }) {
  if (part.type !== "tool-setup_preferences") return null

  return (
    <PreferencesWizard
      {...part.input}
      status={part.state === "input-streaming" ? "streaming" : undefined}
      progress={loadProgress(part.toolCallId)}
      onProgress={(p) => saveProgress(part.toolCallId, p)}
      result={part.state === "output-available" ? part.output : undefined}
      onResult={(result) =>
        addToolResult({
          tool: "setup_preferences",
          toolCallId: part.toolCallId,
          output: result,
        })
      }
    />
  )
}

The agent receives one of:

{
  action: "save",
  answers: {
    topics: ["world", "tech", "climate"],
    sources: ["Harbor Post", "My Local Paper"],
    depth: 4,
    alerts: { breaking: true, followed: false, weekly: true },
  },
  skipped: ["digest"],
}
{ action: "dismiss" }

With LangGraph

Push it from a graph node with ui.push({ name: "setup_preferences", props: { toolCallId, ...args } }, { message }), and render the thread's UI messages with the Renderer.

Restoring from history

There are two ways to restore it, like the Checklist:

PropBehavior
Saved progressonProgress → progressSave { stepIndex, answers, skipped } on every change and pass it back. A half-done wizard resumes on the same step (stepIndex equal to the number of steps is the review). Nothing is sent to the agent
A decisionresultThe user saved or chose "Not now". Renders the read-only record and never calls onResult again
<PreferencesWizard
  {...part.input}
  progress={savedProgress}
  onProgress={(p) => saveProgress(part.toolCallId, p)}
  result={part.state === "output-available" ? part.output : undefined}
/>

Schema

PropTypeNotes
iconWizardIcon?What the preferences are about, in a tinted box beside the step title
titlestringe.g. "Set up your news preferences". Names the card for screen readers and heads the saved record
introstring?One sentence: why, and what it changes. Read to screen readers, not shown
stepsStep[]2–8 steps
allowSkipbooleanOptional steps can be skipped and keep their defaults. Default true
savedTostring?e.g. "your profile". Shown in the saved record and announced on the review

Step: { id, title, description?, required?, input }. description is one short line under the title; don't repeat the pick limit, which the card already shows.

input.typeFieldsNotes
cardsoptions: { id, label, description?, icon?, image? }[], multiple?, min?, max?, value?2–12 options. icon from a fixed set (newspaper, utensils, plane, music, film, book, dumbbell, leaf, briefcase, heart, globe, sparkles, bell, moon, sun, coffee, shopping-bag, home). image: { src, alt }, http(s) or data:image only
chipsoptions: string[], max?, allowCustom?, value?Always multiple
scalemin, max, step, value, minLabel, maxLabel, format?, unit?, currency?format: level ("Adventurous (4 of 5)", default), number, currency, percent
rankitems: { id, label }[]2–8, in the starting order
togglesitems: { id, label, description?, value }[]1–8
scheduledays?, from?, to?Days default to every day, from to 08:00. Set to for a range
textplaceholder?, maxLength?, value?Up to 500 characters

Host props: status (streaming, ready, saved, dismissed), onResult, onProgress, progress, result and className.

Source

On this page