Overview of IO Primitives
Collect user inputs, display messages, and track progress in your tools and agents.
Overview
The IO class is the primary way your tools and agents interact with users. Every handler function receives an io object that provides methods for collecting inputs, displaying messages, and tracking progress.
handler: async ({ io }) => {
// Collect user input
const name = await io.textInput({ label: 'Your name' })
// Show confirmation
const confirmed = await io.confirm({ title: 'Proceed?' })
// Display a message
await io.message({ title: 'Done!', description: `Hello, ${name}` })
}All IO methods are async and will pause execution until the user responds. This enables natural, conversational workflows in your tools.
Input Methods
Collect structured data from users with built-in validation.
Text Input
Collect text, emails, URLs, or secure passwords with validation.
Number Input
Numeric input with min/max constraints.
Date Input
Single date, multiple dates, or date range selection.
Select Input
Dropdowns, radio buttons, checkboxes, and radio cards.
Search Input
Async search with custom search handlers.
Table Input
Interactive tables for row selection.
Form Input
Multi-field forms with Zod validation.
Interaction Methods
Guide users through workflows with confirmations and messages.
Confirm
OK/Cancel dialogs for critical actions and approvals.
Message
Display informational messages, results, or rich content.
Progress Methods
Keep users informed during long-running operations.
Loader
Show loading state during async operations.
Progress Loader
Track progress of batch operations with item counts.
Quick Reference
| Method | Description | Returns |
|---|---|---|
textInput() | Collect text with optional validation | string |
numberInput() | Collect numeric values | number |
dateInput() | Date picker (single, multiple, range) | string | string[] | {from, to} |
selectInput() | Selection from predefined options | value | value[] |
searchInput() | Async search with custom handler | string | string[] |
tableInput() | Row selection from data table | row | row[] |
formInput() | Multi-field form with validation | Record<string, value> |
confirm() | OK/Cancel confirmation dialog | boolean |
message() | Display message to user | void |
loader() | Show loading indicator | LoaderInstance |
progressLoader() | Show progress indicator | ProgressLoaderInstance |
Common Patterns
Validation with Zod
All input methods support Zod validation schemas:
import * as z from 'zod'
const email = await io.textInput({
label: 'Email address',
inputType: 'email',
validationSchema: z.string().email('Please enter a valid email'),
})
const age = await io.numberInput({
label: 'Age',
validationSchema: z.number().min(18, 'Must be 18 or older'),
})Optional Fields
Mark inputs as optional to allow skipping:
const nickname = await io.textInput({
label: 'Nickname',
optional: true, // User can skip this
})
// nickname is string | undefinedDefault Values
Pre-fill inputs with default values:
const count = await io.numberInput({
label: 'Item count',
defaultValue: 10,
})Human-in-the-Loop Confirmations
Add approval gates to critical operations:
const shouldProceed = await io.confirm({
title: 'Delete all records?',
description: 'This action cannot be undone.',
okButtonLabel: 'Delete',
cancelButtonLabel: 'Cancel',
})
if (!shouldProceed) {
return 'Operation cancelled'
}Progress Tracking
Show progress for batch operations:
const items = await fetchItems()
const progress = io.progressLoader({
title: 'Processing items',
itemsInQueue: items.length,
})
for (const item of items) {
await processItem(item)
progress.itemCompleted()
}
progress.close()