Repository navigation
fix: declare @ai-sdk/provider and provider-utils as optional peers - #630
mattapperson wants to merge 3 commits into
Conversation
The published .d.ts files import both packages, but they were only devDependencies, so type resolution depended on the consumer's node_modules layout (silent any under pnpm GVS, arbitrary hoisted copy elsewhere). Declare them as dependencies and let tsup externalize them. Adds scripts/check-consumer-types.mjs and a CI step that packs the package and type-checks a consumer with skipLibCheck: false under pnpm isolated (hoist=false), pnpm hoisted, and npm. Fixes #621
Caret dependencies resolved to the newest @ai-sdk/provider, while ai pins an exact version, so consumers on older ai 7.x got a second copy and generateText/streamText/wrapLanguageModel failed with TS2322. Declare both as optional peerDependencies so the .d.ts imports bind to the copies the consumer's ai version uses, keep them bundled at runtime (as in 3.1.0), and restore the lockfile to main's. Rework check-consumer-types to type-check real user code against a matrix of ai versions (peer floor, devDependency, latest) and package-manager layouts (pnpm isolated, global virtual store, hoisted, npm), plus an end-to-end generateText runtime smoke test.
d7389a9 to
37d8bba
Compare
There was a problem hiding this comment.
Devin Review found 1 new potential issue.
1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)
| @@ -0,0 +1,7 @@ | |||
| --- | |||
| "@openrouter/ai-sdk-provider": minor | |||
There was a problem hiding this comment.
🟡 Bug fix receives a minor version bump
For this dependency-resolution fix, the changeset selects a minor release. The repository's release rules reserve minor bumps for new features, so publication increments the wrong version component.
| "@openrouter/ai-sdk-provider": minor | |
| "@openrouter/ai-sdk-provider": patch |
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Keeping minor on purpose. This changes the published manifest: it adds two new peerDependencies, @ai-sdk/provider and @ai-sdk/provider-utils (both optional), and package managers will now report or check them, for example peer warnings if someone pins an incompatible major. The PR review asked for at least minor so the change is visible in the version number, and the changeset lists the supported ai range. I am leaving this thread open so the maintainer can make the final call on patch vs. minor.
Description
Fixes #621
dist/index.d.tsanddist/internal/index.d.tsimport from@ai-sdk/providerand@ai-sdk/provider-utils, but neither was declared. Under strict layouts (pnpmhoist=false, pnpm global virtual store) the imports failed withTS2307and provider types degraded toany. Under lenient layouts they bound to whatever copy was hoisted.Changes
peerDependencies(optional):@ai-sdk/provider: ^4.0.0,@ai-sdk/provider-utils: ^5.0.0, both withpeerDependenciesMeta.optional: true. They stay indevDependenciesat the versions we build against (4.0.16/5.0.42), sopnpm-lock.yamlis unchanged frommain.noExternalfor both packages. The runtime JS is the same shape as 3.1.0, with no runtime imports of@ai-sdk/*. Optional peers are not guaranteed to be installed, and the copyaibrings can be older than the version we compiled against.scripts/check-consumer-types.mjs(pnpm check:consumer-types) packs the tarball and installs one consumer per (layout,aiversion) outside the repo. It runstscwithskipLibCheck: falseon real user code:generateText/streamTextwith chat, completion, the callable provider, and the internal chat model;wrapLanguageModel;embed/embedMany;createProviderRegistry({ openrouter }); plusIsAnyassertions. Then it runs a runtime smoke test that imports both entries and does an end-to-endgenerateTextthrough the consumer'saiagainst a stubfetch. Any TS error fails the check (TS2307,TS2322,any), with one exception:@ai-sdk/provider's own undeclaredjson-schemaimport (TS7016, global virtual store only). That one is upstream and affectsaiitself.pnpm-isolated(hoist=false),pnpm-global-virtual-store,pnpm-hoisted,npm×ai7.0.0(peer floor),7.0.103(devDependency),latest. That's 12 consumers, run 4 at a time, about 10 s locally with a warm cache.pnpm-isolated-no-auto-peers,npm-legacy-peer-deps.--tarball=<path>checks an arbitrary tarball, for baselines.Why optional peers: comparison
aipins exact versions of@ai-sdk/provider/provider-utils(ai@7.0.0usesprovider@4.0.0,7.0.103uses4.0.16, latest uses4.0.35). If our.d.tsbinds to any other copy, user code failsTS2322once the copies diverge (for example,finishReason.unifiedgained'interrupted'). Results from the harness above (tscresult peraiversion: 7.0.0 / 7.0.103 / latest; runtime passed everywhere):dependencies, externalai's pinned copy, so the earlier claim that they'd dedupe withaiwas wrong.ai's), but npm 7+ auto-installs the newest matching peer at the root and nestsai's pinned copy underai/, so the types diverge.ai's, and npm resolves the hoisted copy, which is alsoai's. I checked this withnpm lsand the pnpm symlinks: onai@7.0.0, our package links@ai-sdk/provider@4.0.0/provider-utils@5.0.0.aifloor, wasn't needed.Runtime duplicates (review finding)
The runtime still bundles a private copy, as in 3.1.0. Cross-copy checks still work because both markers use
Symbol.for:AISDKErrormarkers (Symbol.for('vercel.ai.error…')) and the workflow serde symbols from@workflow/serde(Symbol.for('workflow-serialize')/Symbol.for('workflow-deserialize')).Notes
e2e/issues/issue-621-*.test.tschecks the declarations (optional peers, nothing undeclared insrc/dist.d.ts, no runtime@ai-sdk/*imports indist/*.js). It runs only undertest:issues. The CI guard ischeck:consumer-types.TS2322in the issue's Mastra repro comes from@mastra/corepinning its own@ai-sdk/provider. That has to be fixed on Mastra's side.Checklist
pnpm stylecheckandpnpm typecheckpnpm testand all tests passChangeset
pnpm changesetto create a changeset file (minor)