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,generateObjectorstreamObjectcall (invoke_agent). Under it sit a span for each step, achatspan for each model call, and anexecute_toolspan for each tool execution. Thechatspan 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 byaiversion. - 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 bareobservemakes 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
failedwhen 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
-
Install the SDK and the AI SDK telemetry package. On
ai7,@ai-sdk/otelneeds Node 22 or newer, andinit()registers it for you. Onai5 and 6, addexperimental_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 -
Initialize Rius, wait for
ready, and wrap your attempt and your retry loop in namedobservefunctions. 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 -
generateTextretries failed calls by itself (maxRetries, 2 by default) before it throws, so setmaxRetries: 0when 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. -
Open Traces and select the run. In the waterfall, look for the retry row under your
summarizespan, and expand it to read each attempt’schatspan. -
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
chatspan 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
chatspan, 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
ai7,await client.readylistsvercel-ai, and onai5 and 6 each call needsexperimental_telemetryenabled.