Skip to content

fix(docs): move the AI providers onto the provider spec ai@7 expects - #438

Merged
IgorShevchik merged 1 commit into
mainfrom
fix/ai-sdk-provider-spec
Aug 19, 2026
Merged

fix(docs): move the AI providers onto the provider spec ai@7 expects#438
IgorShevchik merged 1 commit into
mainfrom
fix/ai-sdk-provider-spec

Conversation

@IgorShevchik

Copy link
Copy Markdown
Collaborator

Fixes a break I introduced in #425, which is currently on main.

What broke

#425 aligned dependencies to upstream and took ai from ^6.0.214 to ^7.0.66. It did not touch @ai-sdk/deepseek or @ai-sdk/mcp, because upstream does not declare them — this fork's docs assistant runs on DeepSeek.

The coupling is the provider spec:

package implements
ai@7.0.66 @ai-sdk/provider@**4**.0.7
@ai-sdk/deepseek@2.0.38 @ai-sdk/provider@**3**.0.10
@ai-sdk/mcp@1.0.52 @ai-sdk/provider@**3**.0.10

Two majors of the provider spec in one tree, with the assistant talking across the gap.

The fix

@ai-sdk/deepseek^3.0.28, @ai-sdk/mcp2.0.32, in docs/ and in both Nuxt playgrounds — they declare @ai-sdk/deepseek too, and fixing only docs/ would have left the same mismatch behind. PORTING.md §2's mirror rule, again.

The lockfile now resolves one @ai-sdk/provider@4.0.7, down from two majors. That resolution — not a passing suite — is the load-bearing check here:

$ grep -oE "@ai-sdk/provider@[0-9.]+" pnpm-lock.yaml | sort -u
@ai-sdk/provider@4.0.7

Second finding: a supply-chain policy nearly waived silently

@ai-sdk/mcp is pinned exactly, and that is deliberate.

Reaching for the newest, 2.0.33, published the previous day, made pnpm silently append it to minimumReleaseAgeExclude in pnpm-workspace.yaml rather than refusing. This repo enforces a 24-hour minimum release age; the exclusion waives it for that package, and in a diff it reads as one unremarkable config line.

2.0.32 (published 2026-08-14) carries the same @ai-sdk/provider@4.0.7, so the newer release bought nothing. The exclusion line is gone and pnpm-workspace.yaml has no net change against main.

Mechanical note for whoever hits this next: reverting the manifest is not enough, because pnpm validates the existing lockfile before doing anything and aborts. Its suggested pnpm clean --lockfile rebuilds the whole file and produces a large unrelated diff; taking pnpm-lock.yaml from main and reinstalling re-resolves just the affected packages.

Why nothing caught it

Worth stating, because every gate was green while main was broken:

  • the provider packages peer-depend on zod, not on ai — so pnpm has nothing to warn about;
  • typecheck passes, because the provider is still a valid module with the right shape;
  • docs:generate runs with NUXT_PUBLIC_USE_AI=false and no DEEPSEEK_API_KEY, so the request path is never exercised.

The break would have first appeared to a user.

dep-parity.json (added in #429) could not have caught it either, by construction: it records only packages both trees declare, so a fork-only dependency is outside it. §2 now carries that as an invariant, with the one-line check to run whenever ai moves a major, and the minimumReleaseAgeExclude trap alongside it.

Correcting the record

#425 described the version gap as accidental drift. It was not.

Six ledger entries show the v6 line was a deliberate deferralc8e810ca reads "ai (v6 line, deferred v7), @ai-sdk/vue (v3)", 229b64f6 reads "ai+@ai-sdk/ (v6 line + DeepSeek)"* — and it was deferred for exactly the coupling that then broke. The bump was still the right call and was made on instruction, but it ended a considered decision rather than correcting an oversight, and the record should say so.

Found while checking why upstream's CLAUDE.md commit did not apply here — which surfaced the .gitignore entry added in b55bd3e7, and in that commit's body, the deferral note.

Verify (CI=true)

pnpm install --frozen-lockfile · dev:prepare (all four apps) · lint · typecheck · test · build · docs:generate — all green. Tests 6708 passed | 6 skipped across 294 files. 1240 routes prerendered.

Still not verified

The assistant's runtime path remains unexercised here — no DEEPSEEK_API_KEY, and the build disables it. This PR aligns the provider spec, which is necessary; confirming a real completion still wants one manual request against a live key.


Generated by Claude Code

#425 took `ai` from ^6.0.214 to ^7.0.66 and left the DeepSeek provider
behind. `ai@7` resolves `@ai-sdk/provider@4`; `@ai-sdk/deepseek@2.0.38` and
`@ai-sdk/mcp@1.0.52` implement `@ai-sdk/provider@3`. Two majors of the
provider spec in one tree, with the assistant talking across the gap.

Bumped to ^3.0.28 and 2.0.32, in `docs/` and in both Nuxt playgrounds —
they declare `@ai-sdk/deepseek` too, and fixing only `docs/` would have
left the same mismatch in place. The lockfile now resolves a single
`@ai-sdk/provider@4.0.7`, down from two.

`@ai-sdk/mcp` is pinned exactly rather than with a caret, and that is the
second finding. Reaching for the newest, `2.0.33`, published the previous
day, made pnpm **silently append it to `minimumReleaseAgeExclude`** in
`pnpm-workspace.yaml` instead of refusing — a supply-chain policy waived by
a line that reads as ordinary config. `2.0.32` carries the same
`@ai-sdk/provider@4.0.7`, so the newer release bought nothing; the
exclusion list is back to the single entry it had before.

Nothing in the gate could have caught the version mismatch, which is the
part worth recording. The provider packages peer-depend on `zod`, not on
`ai`, so pnpm stays quiet. `typecheck` passes because the provider is still
a valid module. `docs:generate` runs with NUXT_PUBLIC_USE_AI=false and no
DEEPSEEK_API_KEY, so the request path is never exercised. The break would
have first appeared to a user.

`dep-parity.json` could not have caught it either, by construction: it
records only packages both trees declare, and `@ai-sdk/deepseek` and
`@ai-sdk/mcp` are fork-only — this fork's assistant runs on DeepSeek, so
upstream's `chore(deps)` batches never mention them. §2 now carries that as
an invariant, with the check to run when `ai` moves a major, and the
`minimumReleaseAgeExclude` trap alongside it.

Also corrects the record. #425 described the version gap as accidental
drift. It was not: six ledger entries show the v6 line was a deliberate
deferral — `c8e810ca` reads "ai (v6 line, deferred v7), @ai-sdk/vue (v3)"
and `229b64f6` reads "ai+@ai-sdk/* (v6 line + DeepSeek)" — deferred for
exactly the coupling that then broke. The bump was still the right call and
was made on instruction, but it ended a considered decision rather than
correcting an oversight.

Found while checking why upstream's `CLAUDE.md` commit did not apply here,
which surfaced the `.gitignore` entry added in `b55bd3e7` and, in that
commit's body, the deferral note.

Verify (CI=true): pnpm install --frozen-lockfile · dev:prepare across all
four apps · lint · typecheck · test (6708 passed, 6 skipped, 294 files) ·
build · docs:generate (1240 routes) — all green. The load-bearing check is
not the suite but the resolution: one `@ai-sdk/provider` version across the
whole lockfile.
@IgorShevchik
IgorShevchik force-pushed the fix/ai-sdk-provider-spec branch from 4e1ee4d to bf7d2fc Compare August 19, 2026 13:33
@IgorShevchik
IgorShevchik merged commit e3f48be into main Aug 19, 2026
1 check passed
@IgorShevchik
IgorShevchik deleted the fix/ai-sdk-provider-spec branch August 19, 2026 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants