Vercel AI SDK
The AI SDK does not hand you a provider client to wrap. It hands you a language
model. So Metergraph attaches as AI SDK middleware rather than through
wrap().
This is TypeScript only. There is no Python equivalent, because the AI SDK is a TypeScript library.
Attach the middleware
Section titled “Attach the middleware”import * as mg from "metergraph";import { generateText, wrapLanguageModel } from "ai";import { openai } from "@ai-sdk/openai";
const model = wrapLanguageModel({ model: openai("gpt-5-mini"), middleware: mg.vercelAISDKMiddleware(),});
await mg.trace("support-answer", () => generateText({ model, prompt: "Help this customer" }));generateText and streamText are both covered: the middleware implements
wrapGenerate and wrapStream, so the two calls take the same capture path.
The middleware initializes Metergraph itself the first time it is created, so
you can hand it init() options directly instead of calling init()
separately:
mg.vercelAISDKMiddleware({ repository: "owner/repository", environment: "production",});If your application already calls mg.init() centrally, call it first and pass
the middleware nothing.
AI SDK versions
Section titled “AI SDK versions”The AI SDK’s middleware protocol has its own version number, separate from the
AI SDK release. The middleware defaults to protocol v3, which is what AI SDK
6 uses and what AI SDK 7 still accepts. AI SDK 5 uses protocol v2, so it is
the one case where you have to say something.
| AI SDK | Call | Node.js |
|---|---|---|
| 5 | vercelAISDKMiddleware({ aiSdkVersion: 5 }) | 18 and newer |
| 6 | vercelAISDKMiddleware() | 18 and newer |
| 7 | vercelAISDKMiddleware() | 22 and newer |
Metergraph itself supports Node.js 18 and newer. The Node 22 floor in the last row is the AI SDK 7 release’s own requirement, not Metergraph’s.
aiSdkVersion: 5 is the only accepted value for that option. It exists to map
AI SDK 5 onto protocol v2 without asking you to know the protocol numbers.
The advanced escape hatch
Section titled “The advanced escape hatch”specificationVersion sets the raw middleware protocol version directly, and
accepts "v2", "v3" or "v4". Reach for it only if a future AI SDK needs a
protocol the table above does not cover.
mg.vercelAISDKMiddleware({ specificationVersion: "v4" });Applying it once, not per call site
Section titled “Applying it once, not per call site”Repeating wrapLanguageModel at every call site is how instrumentation gets
missed. Two patterns avoid it.
A provider registry takes the middleware once, and every model it hands out is captured:
import { createProviderRegistry, gateway } from "ai";import { anthropic } from "@ai-sdk/anthropic";import { openai } from "@ai-sdk/openai";import * as mg from "metergraph";
const registry = createProviderRegistry( { anthropic, gateway, openai }, { languageModelMiddleware: mg.vercelAISDKMiddleware() },);
export const model = registry.languageModel("gateway:anthropic/claude-sonnet-4.5");An existing model factory is the other place to put it: wrap the single return path your application already funnels model construction through. Use the registry for new multi-provider code. Do not invent a factory purely for Metergraph.
Both patterns have a runnable example: registry, existing factory.
What a row records
Section titled “What a row records”The middleware records the model ID from the language model, the standardized prompt and the call settings.
It deliberately does not record providerOptions, headers or
abortSignal. Those carry credentials, callbacks and values that do not
serialize, and the standardized prompt and settings are enough to reconstruct
the call.
The endpoint is recorded as ai.doGenerate or ai.doStream.
Provider naming
Section titled “Provider naming”The AI SDK’s provider string is normalized so rows line up with directly wrapped clients:
amazon-bedrock,aws-bedrockandawsall becomebedrockgemini,google-genaiand anything startinggoogle.becomegoogle- a prefixed name such as
openai.chatbecomesopenai - a gateway provider (
gateway,vercel,vercel-ai-gateway) resolves through the model ID’s creator prefix, soanthropic/claude-sonnet-4.5becomesanthropic
See Vercel AI Gateway.
Multi-step tool loops
Section titled “Multi-step tool loops”Each provider request in a multi-step tool loop becomes its own row. That is
the point: a loop that quietly runs six model calls shows six costed rows, not
one. Wrap the whole operation in mg.trace() so they read as one workflow, and
mg.track() or mg.route() to name it.
Streaming
Section titled “Streaming”The middleware wraps the returned stream rather than consuming it. Your
for await loop sees every part, unchanged and in order. Time to first token
comes from the first part that carries real output: a text or reasoning delta,
a tool call, a tool result, a file or a source. The row is finalized when the
stream ends, and a cancelled stream is finalized with an abandoned status
rather than being dropped.
Do not double-instrument
Section titled “Do not double-instrument”Fail-open
Section titled “Fail-open”The middleware is telemetry. If capture cannot start, the call runs
uninstrumented. If capture cannot finish, the row is dropped. Neither reaches
your generateText result or your stream, and a fault while inspecting one
stream part yields that part unchanged and moves on.
The middleware has no runtime dependency on ai. It is a plain object matching
the middleware shape, so installing Metergraph does not pull the AI SDK in.
- Vercel AI Gateway for gateway-routed models
- Name a route for
track()androute() - Serverless and short-lived jobs for Vercel functions and edge runtimes
- TypeScript SDK for the full signature