Vercel AI SDK
axonPushMiddleware is a LanguageModelMiddleware for wrapLanguageModel, recording generateText and streamText calls with usage and finish reason.
axonPushMiddleware returns a LanguageModelMiddleware for the Vercel AI
SDK. Wrap a model with it once and every call through that model is traced,
the call sites themselves do not change.
Tested against ai@^4.
Install
npm install @axonpush/sdk ai
Wrap the model
import { wrapLanguageModel } from "ai";
import { openai } from "@ai-sdk/openai";
import { AxonPush, axonPushMiddleware } from "@axonpush/sdk";
const client = new AxonPush();
const model = wrapLanguageModel({
model: openai("gpt-4o"),
middleware: axonPushMiddleware({
client,
channelId: process.env.AXONPUSH_CHANNEL_ID!,
agentId: "support-bot",
}),
});
Then use the wrapped model everywhere:
import { generateText, streamText } from "ai";
const { text } = await generateText({ model, prompt: "Explain quantum computing." });
const stream = streamText({ model, prompt: "Explain quantum computing." });
agentId defaults to "vercel-ai".
What gets emitted
The middleware implements both wrapGenerate and wrapStream.
| Identifier | axonpush eventType | Payload |
|---|---|---|
llm.start | agent.start | model, prompt_tokens (non-streaming) or streaming: true |
llm.token | agent.llm.token | token, one per text-delta chunk |
llm.end | agent.end | model, usage, finish_reason |
On the streaming path the middleware pipes the model’s stream through a
TransformStream, emitting a token event per delta and reading usage and
finishReason off the terminal finish chunk. Every chunk is passed through
untouched, so your consumer sees exactly what it would without the middleware.
prompt_tokens on a non-streaming llm.start is the length of the prompt
array, not a token count, it is captured before the call, when no token count
exists yet. The real counts arrive on llm.end in usage.
Every event carries metadata.framework: "vercel-ai".