showcase/integrations/mastra/qa/gen-ui-interrupt.md
/demos/gen-ui-interrupt on the dashboard host/api/health); OPENAI_API_KEY is set on RailwayuseInterrupt({ renderInChat: true }). Unlike LangGraph's interrupt(), the
Mastra path is a NATIVE suspend TOOL: the backend schedule_meeting
(src/mastra/tools/interrupt.ts) calls suspend({ topic, attendee, slots }),
the @ag-ui/mastra bridge maps that suspend to an AG-UI interrupt (legacy
on_interrupt CUSTOM event + the standard RUN_FINISHED interrupt-outcome),
and useInterrupt renders the TimePickerCard. Picking a slot resolve(...)s,
which resumes the Mastra run (re-invoking the tool's execute with
resumeData)./demos/gen-ui-interrupt; verify the page renders within 3s with the CopilotChat in a max-w-4xl, full-height, rounded-2xl containerdata-testid="time-picker-card" presentschedule_meeting when explicitly asked to book/schedule)schedule_meeting, the backend tool suspend()s, and a picker renders INLINE with data-testid="time-picker-card"<body>, unlike the hitl-in-app modal) — no body > [data-testid="time-picker-card"]data-testid="time-picker-slot") with the backend-generated labels (relative to now):
data-testid="time-picker-cancel") below the griddata-testid="time-picker-picked" — a "Booked" success badge with the chosen label in bold — and the interactive card unmounts (no time-picker-card)Scheduled "{topic}" for {chosen_label}.)data-testid="time-picker-card"); the "With Alice" attendee line appears next to the eyebrow when the agent supplies an attendeedata-testid="time-picker-cancelled" — a "Cancelled" badge with "No time picked."topic, which comes from the model's tool-call args and is NOT deterministic — do not assert on the topic text{chosen_time, chosen_label}) or "None of these work" ({cancelled: true}); post-resolution the card is read-only