Human-in-the-Loop
FlowDrop’s interrupt system enables workflows to pause execution and request user input before continuing. This is essential for approval workflows, data collection, decision points, and quality control.
Interrupt Types
Section titled “Interrupt Types”Confirmation
Section titled “Confirmation”Simple yes/no prompt for binary decisions:
{ "interrupt_type": "confirmation", "message": "Do you approve sending this email to 150 recipients?", "confirm_label": "Yes, send email", "cancel_label": "No, cancel"}Response: boolean
Choice
Section titled “Choice”Single or multiple selection from predefined options:
{ "interrupt_type": "choice", "message": "Select the output format:", "options": [ { "value": "json", "label": "JSON", "description": "Structured data" }, { "value": "csv", "label": "CSV", "description": "Spreadsheet format" } ], "multiple": false}Response: string (single) or string[] (multiple)
Text Input
Section titled “Text Input”Free-form text entry:
{ "interrupt_type": "text_input", "message": "Provide additional context:", "placeholder": "Enter your notes...", "multiline": true, "max_length": 1000}Response: string
Complex data entry using JSON Schema:
{ "interrupt_type": "form", "message": "Complete the configuration:", "schema": { "type": "object", "properties": { "priority": { "type": "string", "enum": ["low", "medium", "high"] }, "notify": { "type": "boolean", "title": "Send notification" } } }, "default_values": { "priority": "medium", "notify": true }}Response: object (matching schema structure)
Review
Section titled “Review”Review proposed field changes with per-field accept/reject decisions and visual diffs:
{ "interrupt_type": "review", "message": "Review these proposed changes:", "changes": [ { "field": "title", "label": "Page Title", "original": "About Us", "proposed": "About Our Company" }, { "field": "body", "label": "Body Content", "original": "<p>Welcome to our site.</p>", "proposed": "<p>Welcome to our company website.</p>" } ]}Response: ReviewResolution with per-field decisions and summary counts.
Architecture
Section titled “Architecture”Frontend Integration
Section titled “Frontend Integration”The ChatPanel automatically detects and renders interrupts in messages. For manual integration:
import { interruptService, interruptActions, getPendingInterrupts, getInterrupt} from '@flowdrop/flowdrop/playground';
// Read pending interrupts reactivelyconst pending = $derived(getPendingInterrupts());
// Resolve an interruptasync function resolveInterrupt(interruptId: string, value: unknown) { const result = interruptActions.startSubmit(interruptId, value); if (!result.valid) return;
try { await interruptService.resolveInterrupt(interruptId, value); interruptActions.submitSuccess(interruptId); } catch (error) { interruptActions.submitFailure(interruptId, String(error)); }}Using Prompt Components Directly
Section titled “Using Prompt Components Directly”<script lang="ts"> import { ConfirmationPrompt } from '@flowdrop/flowdrop/playground';</script>
<ConfirmationPrompt config={{ message: 'Do you approve this action?', confirm_label: 'Approve', cancel_label: 'Reject' }} status="pending" allowCancel={true} onConfirm={() => handleConfirm()} onCancel={() => handleCancel()}/>Backend Integration
Section titled “Backend Integration”Message Metadata Format
Section titled “Message Metadata Format”When a workflow requires input, the backend sends a message with interrupt metadata:
{ "id": "msg-123", "role": "assistant", "content": "I need your approval to proceed.", "metadata": { "type": "interrupt_request", "interrupt_id": "int-456", "interrupt_type": "confirmation", "message": "Do you approve this action?", "confirm_label": "Approve", "cancel_label": "Reject" }}API Endpoints
Section titled “API Endpoints”| Endpoint | Method | Purpose |
|---|---|---|
/interrupts/{id} | GET | Get interrupt details |
/interrupts/{id} | POST | Resolve interrupt |
/interrupts/{id}/cancel | POST | Cancel interrupt |
/playground/sessions/{id}/interrupts | GET | List session interrupts |
State Management
Section titled “State Management”The interrupt store uses a state machine with these transitions:
- idle — Awaiting user input
- submitting — User response being sent
- resolved — Successfully processed
- error — Submission failed (can retry)
Resolved interrupts remain visible but disabled, showing the user’s selection.
Best Practices
Section titled “Best Practices”- Clear messages — Write actionable prompts (“Do you approve sending this email to 150 recipients?” not “Proceed?”)
- Meaningful labels — Use descriptive button labels (“Yes, send email” not “Yes”)
- Default values — Provide sensible defaults for form fields
- Cancel behavior — Only set
allowCancel: falsefor mandatory interrupts - Error handling — Always handle resolution failures gracefully