Repository navigation
fix: keep the provider user agent when called through the AI SDK - #603
Open
LukasParke wants to merge 2 commits into
Open
LukasParke wants to merge 2 commits into
LukasParke wants to merge 2 commits into
Conversation
LukasParke
added a commit
that referenced
this pull request
Oct 23, 2026
…lict with #603 The image model already shallow merges provider routing (#551); moving it onto mergeProviderRouting was a pure refactor, and its new import landed on the same line as #603's user-agent import. Keep image/index.ts as on main so the two PRs merge in either order. No behaviour change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
5 tasks done
The AI SDK passes its own user-agent call header, and call headers were merged last with combineHeaders, so the ai-sdk/openrouter/<version> identifier was dropped for generateText, embed, generateImage and the rest. Headers are now combined with combineHeadersWithUserAgent, which appends the identifier to the call-level user agent. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A custom call-level user-agent on a direct model call is used verbatim again; the identifier is only appended when the call-level value carries the AI SDK's ai/<version> token. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LukasParke
force-pushed
the
claude/user-agent-suffix
branch
from
November 10, 2026 19:11
a34c2b6 to
9c81ee0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Bug. Requests made through the AI SDK lose the provider's
ai-sdk/openrouter/<version>user agent identifier. The AI SDK passes its ownuser-agent(ai/<version>) in the call-level headers, and every model merged headers withcombineHeaders(this.config.headers(), options.headers), which puts call headers last. So the SDK's value replaced ours. A directdoGeneratecall has no call-level UA, so it kept the identifier, which is why the existing tests didn't catch this.Repro.
What other providers do.
@ai-sdk/openai(latest) builds its config headers the same way, withwithUserAgentSuffix({...}, 'ai-sdk/openai/<v>')and thencombineHeaders(this.config.headers?.(), options.headers).combineHeadersin@ai-sdk/provider-utils(latest) is still a plain spread, so first-party providers lose their identifier throughaitoo. RunningwithUserAgentSuffixafter combining won't work here either: our version (#362, fixes #300) uses any existing UA verbatim, so it would just keepai/<v>.Fix. New
combineHeadersWithUserAgent(configHeaders, callHeaders)insrc/utils/with-user-agent-suffix.ts. It combines the headers like before. When the config UA is the default provider identifier and the call-level UA comes from the AI SDK (it contains anai/<version>token) without the identifier, it sends<call UA> ai-sdk/openrouter/<v>. For example,ai/7.0.103 ai-sdk/openrouter/3.1.0 ai-sdk/provider-utils/... runtime/....User-Agent(Openrouter AI SDK provider overrides/silently rewrites user-specified headers #300) is still never modified.ai/<v>token, e.g.doGenerate({ headers: { 'user-agent': 'my-app/1.0' } }), is still sent verbatim (raised in review). Throughai, a user's call-level UA becomesmy-app/1.0 ai/<v>, and that one does get the identifier appended.It replaces
combineHeaderseverywhere headers are combined: chat (doGenerate,doStream), completion (doGenerate,doStream), embedding, image, video, reranking and evaluation.Not changed. Through
ai, a user-specified provider-levelUser-Agentis still replaced by the SDK's call UA. That is existing behavior and a separate question from this bug.Tests.
src/tests/user-agent.test.tsdrives the realaifunctions with a mockedfetchand asserts the final UA contains bothai/<v>andai-sdk/openrouter/<v>:generateText(chat and completion),embed,generateImage,experimental_generateVideo,experimental_evaluate.streamTextandrerankin the pinnedai7.0.103 send noai/<v>UA, so for those the test asserts that the provider identifier is present. It also checks that a user-specified provider UA, and a custom call-level UA on a directdoGenerate, don't get the identifier appended.src/utils/with-user-agent-suffix.test.tsadds unit tests for the helper: append, case-insensitive match, no call UA, no duplication, custom call UA without theai/token, custom provider UA.I checked that the 6
ai-driven assertions (chat, completion, embed, image, video, evaluate) fail onorigin/mainand pass with this fix.Checklist
pnpm stylecheckandpnpm typecheckpnpm testand all tests passChangeset
pnpm changesetto create a changeset file🤖 Generated with Claude Code