Skip to content

fix: preserve usage for dynamically loaded AI SDK V2 providers - #50414

Closed
devcy0922 wants to merge 1 commit into
anomalyco:devfrom
devcy0922:fix/v2-provider-usage-loss
Closed

devcy0922 wants to merge 1 commit into
anomalyco:devfrom
devcy0922:fix/v2-provider-usage-loss

Conversation

@devcy0922

@devcy0922 devcy0922 commented Sep 21, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #50338

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Provider.getLanguage() is typed as returning LanguageModelV3, but a dynamically loaded provider can hand back a runtime LanguageModelV2 instead. session/llm.ts always passed that model through wrapLanguageModel(). Looking at wrapLanguageModel's implementation in the ai package, the object it returns is hardcoded to specificationVersion: "v3" and calls the wrapped model's doGenerate/doStream directly — it doesn't itself do any V2→V3 conversion. AI SDK has its own compatibility shim for this (asLanguageModelV3, used inside resolveLanguageModel), but that shim only runs when streamText sees a model whose specificationVersion is still "v2". Since wrapLanguageModel already relabels it "v3" before streamText ever looks at it, the shim never fires and the V2 usage numbers (a different shape than V3) never get converted — they come back undefined.

That matters beyond the usage indicator: session/overflow.ts uses that usage to decide when to auto-compact, so with it undefined compaction never triggers and long sessions on these providers just keep growing until the provider hard-rejects the request.

Fix: check the runtime specificationVersion before wrapping. V3 models go through wrapLanguageModel() exactly as before. V2 models skip the wrapper — the message transform that used to run inside transformParams gets applied directly to the ModelMessage[] input instead, and the raw V2 model is passed straight to streamText, so AI SDK's own compat layer does the conversion the way it's meant to.

How did you verify your code works?

  • Wrote a standalone script against wrapLanguageModel/streamText directly (not opencode code) with a hand-built V2 model to confirm the mechanism: wrapping it drops usage, passing it unwrapped preserves it. This matches the reporter's own differential probe in the issue.
  • Added a regression test in test/session/llm.test.ts with a small fixture provider (test/session/fixtures/fake-v2-provider.ts) that implements LanguageModelV2 and is loaded via npm: "file://...", the same mechanism any dynamically loaded provider uses. It goes through the real Provider.getLanguage() → LLM.Service.stream() path. Checked it fails on the pre-fix code (usage undefined) and passes with the fix.
  • bun run typecheck in packages/opencode — clean.
  • bun test test/session/llm.test.ts — 31/31 pass.
  • bun test test/session/ (full directory) — 413 pass, 0 fail, no regressions.

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Provider.getLanguage() is typed as returning LanguageModelV3, but a
dynamically loaded provider can return a runtime V2 model. Routing every
model through wrapLanguageModel() unconditionally labels the result "v3"
(ai/src/middleware/wrap-language-model.ts), which skips AI SDK's own
V2->V3 compat conversion (asLanguageModelV3 inside resolveLanguageModel)
and silently drops finish-step usage. Because session/overflow.ts relies
on that usage to detect context pressure, affected providers never
trigger automatic compaction.

Route V2 models around the wrapper instead: apply the same message
transform directly to the ModelMessage[] input and pass the raw model to
streamText, so AI SDK's built-in compat layer still runs.

Fixes anomalyco#50338

Co-Authored-By: Claude Sonnet 5 <[email protected]>
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Sep 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Sep 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@thdxr

thdxr commented Oct 10, 2026

Copy link
Copy Markdown
Member

This branch has been upgraded to V2. We're no longer taking PRs for V1. If you think this is still relevant, please port it over and open it for V2.

— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

@thdxr thdxr closed this Oct 10, 2026
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.

bug: AI SDK V2 providers silently lose usage and disable auto-compaction

2 participants