Skip to Content

How do I see retries and fallbacks for calls to the Vercel AI SDK?

Rius shows each Vercel AI SDK model call as its own chat span, and a retry loop you wrap in your own span reads as one retry row. A run that failed along the way and still finished is badged recovered. The trace page shows all of this in the waterfall, and the Spans tab lists the model calls on their own.

How it works

The Vercel AI SDK integration records the calls. Your own span gives them a shape you can read.

  • What the integration records. A span for each generateText, streamText, generateObject or streamObject call (invoke_agent). Under it sit a span for each step, a chat span for each model call, and an execute_tool span for each tool execution. The chat span carries the messages, the resolved model, token usage and a cost computed by Rius. Streamed calls carry time to first token. See the Vercel AI SDK integration for the details by ai version.
  • What needs your own span. Wrap a retry loop or a fallback chain you write yourself in observe. Without a wrapper, each call arrives as its own standalone trace. With one, every attempt sits inside your agent’s run. A bare observe makes a chain span named after the function.
  • Where it shows. On the trace page, back-to-back calls of the same step with the same input collapse into one row such as summarize · 3 attempts · recovered, when every attempt but the last failed. Expand the row to see each attempt. Repeated calls that all succeeded stay separate rows.
  • Recovered runs. A trace is failed when any span errored. If the root span finished without an error of its own, the trace is badged recovered. The errors are still counted. Only the verdict changes.

For how the trace page reads, see Exploring traces. For the wider picture of watching agents, see Monitor AI agents in production.

Set it up

  1. Install the SDK and the AI SDK telemetry package. On ai 7, @ai-sdk/otel needs Node 22 or newer, and init() registers it for you. On ai 5 and 6, add experimental_telemetry: { isEnabled: true } to each call instead. The integrations overview covers enabling and disabling integrations.

    npm install @glassflow-ai/rius @opentelemetry/api npm install @ai-sdk/otel
  2. Initialize Rius, wait for ready, and wrap your attempt and your retry loop in named observe functions. The integration already records the model call inside, so you add no generation of your own and nothing is counted twice.

    import { init, observe } from '@glassflow-ai/rius' import { openai } from '@ai-sdk/openai' import { generateText } from 'ai' const rius = init({ apiKey: 'ri_...', serviceName: 'my-agent' }) await rius.ready // the AI SDK integration is registered before the first call const attempt = observe(async function summarizeAttempt(prompt: string) { const { text } = await generateText({ model: openai('gpt-4o-mini'), prompt, maxRetries: 0, // the loop below does the retrying }) return text }) const summarize = observe(async function summarize(prompt: string) { let lastError: unknown for (let i = 0; i < 3; i++) { try { return await attempt(prompt) } catch (err) { lastError = err } } throw lastError }) await summarize('Summarize this ticket') await rius.shutdown() // export queued spans before the process exits
  3. generateText retries failed calls by itself (maxRetries, 2 by default) before it throws, so set maxRetries: 0 when your own loop retries, or each of your attempts can hide up to three provider calls. Name the wrapped functions. An anonymous function traces as anonymous, and a clear name is what the retry row shows.

  4. Open Traces and select the run. In the waterfall, look for the retry row under your summarize span, and expand it to read each attempt’s chat span.

  5. To list only the model calls, open the Spans tab and choose LLM in the All kinds menu. Each row shows tokens, cost and duration, so you can sort by any of them.

What you get

  • One chat span for each model call, with its resolved model, token counts and a list-price cost estimate in US dollars. A call that reported no token usage shows a blank cost, not $0.
  • A retry loop that reads as one event instead of a wall of identical spans, with the individual attempts one click away.
  • A fallback to another model that appears as its own chat span, so the model that answered is visible on the span’s Model section.
  • A recovered badge on runs where child spans failed but the run itself finished clean, so you can tell a retried run from a real failure.
  • A Context growth strip above the tree for traces with several model calls. It plots input tokens per call in order.
  • Compare runs and JSON export on the trace page, to put a retried run next to a clean one or to attach it to a bug report.

When something else fits

  • If you want a plain list of every model call across all runs, the Spans tab filtered to LLM is quicker than reading trace trees.
  • If a call fails before any span is recorded, there is nothing to collapse, so check that the integration attached: on ai 7, await client.ready lists vercel-ai, and on ai 5 and 6 each call needs experimental_telemetry enabled.

Still stuck? Get help

Last updated on