@silverprotocol/vercel-ai
AgJSON normalizer for the Vercel AI SDK —
ai (streamText fullStream
TextStreamPart → AgEvent[]). It sits on top of your streamText
call and translates the stream parts it yields into framework-neutral
AgJSON; it doesn't replace the SDK you already use.
Install
npm install @silverprotocol/vercel-ai ai
@silverprotocol/core is a required peer (pulled in automatically). ai is
the Vercel AI SDK itself — you need it to produce the stream parts. (The
normalizer guards TextStreamParts structurally, so if you only feed it
already-captured parts it's just a type-level peer.)
Upstream compatibility
Supported peer range: ai >=6.0.0 <8 (npm-enforced, optional — this package never imports the SDK).
Wire shapes outside the verified set never crash the normalizer, and the
fixture-drift gate (scripts/check-fixture-drift.mjs) turns every newly-appeared
upstream field into a tracked triage disposition rather than an unnoticed drop —
carried losslessly where a carry channel exists (see sdk-surface.json for this
facet's per-field dispositions, including its disclosed silently-dropped gaps).
ai |
verified | with | evidence |
|---|---|---|---|
7.0.31 |
2026-07-20 | 0.3.3 | LIVE conformance capture: echo-gpt56 corpus (gpt-4o-mini via @ai-sdk/openai, official @ai-sdk/mcp Streamable-HTTP client against the harness mock) — landed as a standing replay seed; full two-step tool loop normalized (tool.start/args/assembled/done -> text step -> turn.done), zero unparsed/frame carries; deterministic replay green across the corpus. Census dispositions seeded from the capture (disclosed drops: tool-input-start.toolMetadata.clientName, dynamic flag on input-start) |
7.0.26 |
2026-07-20 | 0.3.3 | full drive switch + 20-test fixture suite replaying REAL mock-captured fullStream sequences at ai@7.0.26 (text/reasoning/two-step tool with id-correlation R1, per-step message model R3, three error arms R4, abort ordering R5, content-filter mapping, forward-compat frame carries) incl. Reducer folds; D1 burn-down contract finals empirically verified; live conformance capture pending |
Usage
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
import { createVercelNormalizer } from "@silverprotocol/vercel-ai";
// Call streamText as usual — this package normalizes what it emits.
const result = streamText({
model: openai("gpt-5.6"),
tools: { echo: echoTool },
prompt: "call the echo tool",
});
const n = createVercelNormalizer();
const agEvents = [];
// fullStream is the typed TextStreamPart stream (on ai v7 it is aliased to
// `result.stream` — both names work across the supported range).
for await (const native of result.fullStream)
agEvents.push(...n.push(native)); // one TextStreamPart → 0+ AgEvents
agEvents.push(...n.flush()); // seal anything still open
push() returns the AgEvent[] synthesized from each native
TextStreamPart; flush() drains buffered end-of-stream state. Any
async/sync iterable of TextStreamParts works — a live streamText run, or
parts you captured earlier.
Then fold the resulting AgEvents into messages and turns with
@silverprotocol/core's reduce() — the same client code regardless of which
framework produced the stream.
Spec: silverprotocol.io/AgJSON — canonical
in silverprotocol/AgJSON; wire
version 1.0.0-draft.1.