This determines which frameworks and tools are available.
<QuestionFlow id="question-flow-project-setup" steps={[ { "id": "language", "title": "Select a programming language", "description": "This determines which frameworks and tools are available.", "options": [ { "id": "python", "label": "Python" }, { "id": "typescript", "label": "TypeScript" }, { "id": "go", "label": "Go" } ] }, { "id": "framework", "title": "Choose a framework", "description": "Pick the framework you're most comfortable with.", "options": [ { "id": "fastapi", "label": "FastAPI" }, { "id": "django", "label": "Django" }, { "id": "flask", "label": "Flask" } ] }, { "id": "database", "title": "Select your database", "description": "Your data will be stored and queried from here.", "options": [ { "id": "postgres", "label": "PostgreSQL" }, { "id": "mysql", "label": "MySQL" }, { "id": "mongodb", "label": "MongoDB" } ] } ]} onComplete={(answers) => console.log("Complete:", answers)}/>AI generates each step dynamically based on previous answers
Define all steps upfront, component manages navigation internally
Each step can allow one choice or multiple selections
Display a summary of completed configuration choices
QuestionFlow has two modes:
Pass step, title, and options to render a single step. The AI controls progression by generating new steps based on user selections.
Where should we store your data?
<QuestionFlow id="question-flow-database" step={2} title="Select database type" description="Where should we store your data?" options={[ { "id": "postgres", "label": "PostgreSQL", "description": "Open source with strong SQL support" }, { "id": "mysql", "label": "MySQL", "description": "Widely supported, good for web applications" }, { "id": "sqlite", "label": "SQLite", "description": "Embedded, no setup required" } ]} onSelect={(ids) => console.log("Selected:", ids)} onBack={() => console.log("Go back")}/>Pass steps with all step definitions. The component manages internal state and navigation.
Set selectionMode="multi" to allow multiple selections per step.
Choose all the features you want in your project.
<QuestionFlow id="question-flow-features" step={3} title="Select features to include" description="Choose all the features you want in your project." options={[ { "id": "auth", "label": "Authentication", "description": "User login and registration" }, { "id": "api", "label": "REST API", "description": "API endpoints for external access" }, { "id": "admin", "label": "Admin Panel", "description": "Dashboard for managing content" }, { "id": "analytics", "label": "Analytics", "description": "Track user behavior and metrics" } ]} selectionMode="multi" onSelect={(ids) => console.log("Selected:", ids)} onBack={() => console.log("Go back")}/>Pass choice with a title and summary to show what was configured.
<QuestionFlow id="question-flow-receipt" choice={{ "title": "Project configured", "summary": [ { "label": "Language", "value": "Python" }, { "label": "Framework", "value": "FastAPI" }, { "label": "Database", "value": "PostgreSQL" }, { "label": "Features", "value": "Auth, API, Admin" } ] }}/>The receipt state:
Copy components/tool-ui/question-flow and the shared directory into your project. The shared folder contains utilities used by all Tool UI components. The tool-ui directory should sit alongside your shadcn ui directory.
This component requires the following shadcn/ui components:
pnpm dlx shadcn@latest add button separator"use client";import { makeAssistantTool } from "@assistant-ui/react";import { QuestionFlow, QuestionFlowErrorBoundary, parseSerializableQuestionFlow, SerializableQuestionFlowSchema, type SerializableQuestionFlow,} from "@/components/tool-ui/question-flow";export const ConfigureProjectTool = makeAssistantTool< SerializableQuestionFlow, Record<string, string[]>>({ toolName: "configureProject", description: "Guide user through project configuration.", parameters: SerializableQuestionFlowSchema, render: ({ args, result, addResult, toolCallId }) => { if (!args || typeof args !== "object") return null; const questionFlow = parseSerializableQuestionFlow({ ...args, id: (args as any)?.id ?? `wizard-${toolCallId}`, }); return ( <QuestionFlowErrorBoundary> {result !== undefined ? ( <QuestionFlow id={questionFlow.id} choice={{ title: "Project configured", summary: Object.entries(result).map(([key, values]) => ({ label: key, value: values.join(", "), })), }} /> ) : ( <QuestionFlow {...questionFlow} onComplete={(answers) => addResult(answers)} /> )} </QuestionFlowErrorBoundary> ); },});Mount <ConfigureProjectTool /> under <AssistantRuntimeProvider> to register the tool and its UI.
Prop
Type
Prop
Type
Prop
Type
Prop
Type
Prop
Type