AI coding assistants write library code from memory. When a library ships a big release that renames or removes things, the assistant keeps writing the old version. It reads fine & it doesn't build.
SDKProof measures how often that happens. It gives a model real coding jobs for one library, then compiles every answer against the real installed package with tsc, the TypeScript compiler. A task passes only if it compiles — no AI judges another AI.
This page is the Vercel AI SDK, the ai package. Fourteen ordinary jobs — generate some text, stream it, call a tool, get structured output back — one shot each, no docs, no retries.
10 of the 14 compiled. All four misses are the same move: the task asks for a callback pulled out into its own named function, which means writing down its type, and v7 deleted the type names the model reaches for.
This measures the model, not the AI SDK.
Every failure has the same shape. The model names a type that v7 removed. None of the four carried a deprecation warning in v6, so nothing in the training data ever said to stop using them — they were correct one release and gone the next.
ai 7.0.30
import type {
StreamTextOnFinishCallback
} from "ai";
export const handleFinish:
StreamTextOnFinishCallback<never> =
async ({ text, usage }) => {
log(text, usage);
};error TS2724: '"ai"' has no exported member named 'StreamTextOnFinishCallback'. Did you mean 'StreamObjectOnFinishCallback'? error TS7031: Binding element 'text' implicitly has an 'any' type.
ai 7.0.30
// v7 deleted the name. Leave the callback
// inline and TypeScript works out the type:
await streamText({
model,
prompt,
onFinish: async ({ text, usage }) => {
log(text, usage);
},
});tsc --noEmit — 0 errors
ai 7.0.30
import type {
TelemetrySettings,
ToolCallOptions,
} from "ai";
export const telemetry:
TelemetrySettings = {
isEnabled: true,
};error TS2305: Module '"ai"' has no exported member 'TelemetrySettings'. error TS2305: Module '"ai"' has no exported member 'ToolCallOptions'.
ai 7.0.30
import type {
TelemetryOptions,
ToolExecutionOptions,
} from "ai";
export const telemetry:
TelemetryOptions = {
isEnabled: true,
};tsc --noEmit — 0 errors
The compiler sends you to the wrong function. StreamTextOnAbortCallback, StreamTextOnChunkCallback and StreamTextOnErrorCallback all survived v7 — only the finish ones went. So the did-you-mean for the missing StreamTextOnFinishCallback is StreamObjectOnFinishCallback — a different function's callback. A developer who takes the suggestion ends up with streamObject's type while writing streamText. StreamTextOnStepFinishCallback fails the same way and points at GenerateTextOnStepFinishCallback.
Then the second error lands. Once the type is gone, the callback's arguments have nothing describing them, so tsc reports text as an implicit any. One missing name produces a page of errors.
Reading the errors. TS2724 is "that export doesn't exist, did you mean this one". TS2305 is "that export doesn't exist" with no suggestion at all. TS7031 is "I can't tell what type this argument is". All three are the compiler's own words.
Text generation, streaming, structured output, embeddings, message arrays, the renamed maxOutputTokens and the whole tool API all type-check against the real v7.
Write the callback inline and TypeScript infers its type from where it sits — the removed names never come up, so the code compiles. The four failures all start the same way: someone pulls a handler out into its own function and now has to name the type by hand.
Which makes this a narrow, specific gap rather than a general one. The model knows v7. It doesn't know which type names v7 kept.
This library has now shown the whole cycle. A tool rename in mid-2025 was a gap the previous model fell into: 90. Opus 5, trained later, had absorbed it: 100. Then v7 shipped in June 2026, removed four exported type names, and the same model scores 71.
Nothing about the model got worse. The gap closed and a new release opened a new one, on one library, over about a year. That's why a single number is worth less than the direction it's moving.
What decides the size of the gap is how much warning there was. An API marked deprecated for a year or two gets absorbed long before it's deleted — the model has read a thousand migration notes about it. An API that's correct in one release and gone in the next leaves no trail. None of these four names carried a deprecation warning, which is why they're still being written.
React Router shows the other side of that: it removed a lot in v8 and still scores 93, because most of those removals had been signposted for years.
Fourteen realistic AI SDK tasks, written by claude-opus-5, each dropped into a small project with ai 7.0.30, @ai-sdk/openai and zod actually installed, then run through tsc --noEmit. A task passes only if it compiles. The prompts name the function to write, never the type names.
claude-opus-5. Another model will score differently — this same set scored 90 on Opus 4.8, against an earlier version of the package.tsc, the TypeScript compiler, checks that the API exists and the types line up. It never runs the code, so nothing here says a stream behaves properly.claude-opus-5 remembers of the AI SDK, not about the AI SDK's design.v9 renamed the main hook. The model wrote v8 every time.
Queries are clean. It still builds the client the v6 way.
One miss: revalidateTag() takes two arguments now.
The unified error option and the 2-argument z.record().
Name any TypeScript package & I'll run it. Or do it yourself — it's all open source.
There's no npm package. Clone the repo, point it at a library, run it. The compiler is the judge.