Skip to main content
Async iterator tools yield progress updates as they execute, letting you show real-time feedback for long-running operations. Instead of a blank loading spinner while the agent searches, scrapes, or processes data, users see a live progress bar with status details.

What are async iterator tools?

Standard tools execute and return a single result. Async iterator tools are different — they yield intermediate progress updates during execution before producing a final result. This is implemented using async generators on the server side. Consider a web search tool that crawls multiple pages:
  1. Start searching → yield { status: "starting", completed: 0, total: 5 }
  2. First page crawled → yield { status: "searching", completed: 1, total: 5, latest: "example.com" }
  3. Second page crawled → yield { status: "searching", completed: 2, total: 5, latest: "docs.org" }
  4. …and so on until complete
Each progress update streams to the client in real time via the toolProgress property on useStream.

Use cases

  • Web scraping — crawling multiple URLs with per-page progress
  • File processing — batch transformations on uploaded documents
  • Database queries — scanning large datasets with row-count progress
  • API aggregation — calling multiple third-party APIs sequentially
  • Code analysis — linting or testing across multiple files
  • Data pipelines — ETL steps with stage-level progress

The toolProgress property

The useStream hook exposes toolProgress, an array of ToolProgress objects representing active and recently completed tool executions:

Accessing toolProgress from useStream

Define a TypeScript interface matching your agent’s state schema and pass it as a type parameter to useStream for type-safe access to state values. In the examples below, replace typeof myAgent with your interface name:

Building a ToolProgressCard

The ToolProgressCard component renders a visual progress bar with status information for each active tool execution:

Status mapping

Map the tool’s state to user-friendly labels and colors:

Styling the progress card

Calculating progress percentage

The percentage calculation is straightforward but needs guard checks for missing data:
Some tools may not report total upfront (e.g., when the number of items isn’t known until partway through execution). In these cases, consider showing an indeterminate progress indicator instead of a bar at 0%.

Indeterminate progress fallback

Filtering completed progress

Once a tool completes, you typically want to remove its progress card and let the final result appear in the message stream. Filter by state:
Alternatively, keep completed cards visible briefly with a fade-out animation:

Combining with regular tool calls

Async iterator tools and standard tool calls can coexist in the same agent. The final result of an async iterator tool appears in the message stream as a regular tool response, while progress updates come through toolProgress.
Position progress cards inline with messages rather than in a separate panel. This creates a natural reading flow where users see the progress update followed by the result in the same conversation thread.

Handling multiple concurrent tools

An agent may execute multiple async iterator tools in parallel. Each has its own toolCallId, so they render as separate progress cards:
When multiple tools run simultaneously, consider stacking their progress cards vertically with clear labels so users can distinguish between them:

Complete example

Best practices

Progress updates arrive at the rate the server yields them. If updates are too frequent (e.g., per-row in a million-row scan), throttle rendering on the client side to avoid DOM thrashing.
  • Show the latest item — displaying data.latest gives users a sense of what is being processed, not just how much
  • Use transitions on the progress bartransition: width 0.3s ease makes the bar animate smoothly between updates
  • Handle missing totals — fall back to an indeterminate progress bar when data.total is not yet known
  • Clean up completed cards — remove or fade out progress cards once the tool finishes to keep the UI uncluttered
  • Throttle rapid updates — if progress updates arrive faster than 60fps, debounce the state updates to maintain smooth rendering
  • Provide cancel affordance — if the agent supports interruption, add a cancel button to the progress card so users can abort long-running tools