Skip to content

Set a base User-Agent and append agent/<id> when a coding agent is detected#509

Draft
ctufts wants to merge 1 commit into
mainfrom
ctufts/AGI-1012-node-user-agent-tag
Draft

Set a base User-Agent and append agent/<id> when a coding agent is detected#509
ctufts wants to merge 1 commit into
mainfrom
ctufts/AGI-1012-node-user-agent-tag

Conversation

@ctufts

@ctufts ctufts commented Jul 17, 2026

Copy link
Copy Markdown

Summary

The Node SDK doesn't send its own User-Agent today; requests just get got's default (got/11.8.5 ...). This PR gives us a real one: mapbox-sdk-js/<version> on every request, with agent/<id> appended when the process env shows we're running under a coding agent (Claude Code, Codex, Cursor, etc.).

This changes the User-Agent on every Node request the SDK makes, which shows up in server-side logs for every consumer. Calling that out explicitly since it needs reviewer sign-off before merge.

Changes

  • lib/helpers/agent-detect.js (new): Node-only detectAgent(). Checks a hardcoded allowlist of about 24 known coding-agent env indicators in priority order, then falls back to AI_AGENT/AGENT if set. Fallback values get validated against a safe charset (/^[\w.-]{1,64}$/) first, since an env var could contain anything and a stray newline shouldn't be able to crash every request. Returns null outside Node (browser bundle) or if reading process.env throws.
  • lib/helpers/sdk-version.js (new): resolves mapbox-sdk-js/<version> from package.json at runtime so the UA can't drift from the published version.
  • lib/classes/mapi-request.js: defaultHeaders now always sets user-agent, appending agent/<id> when detected. A caller-supplied User-Agent still overrides it, no duplicate header.
  • lib/browser/browser-layer.js: filters user-agent out before calling xhr.setRequestHeader, since browsers won't let scripts set User-Agent via XHR. This is what broke while testing the change (see Testing below). Browser agent-tagging itself is out of scope here; that'll need its own mechanism.
  • rollup.config.js / package.json: added rollup-plugin-json so the UMD browser bundle can inline the version for sdk-version.js.

Testing

Full suite passes (490/490), with new coverage for the allowlist, the AI_AGENT/AGENT fallback and its charset validation (including a header-injection attempt with an embedded newline), the Node/browser guard, and the header merge/override path. Lint and bundle both clean. Manually verified against a real MapiRequest: CLAUDECODE=1 produces mapbox-sdk-js/0.16.3 agent/claude-code, a clean env produces just the base UA, and an AI_AGENT value with a newline gets rejected without crashing.

Downstream impact

Every Node consumer's requests to api.mapbox.com will show a new User-Agent going forward. Worth knowing if anyone has UA-based logging, analytics, or allowlisting downstream. No change for browser consumers (the header gets filtered before it reaches the network, same as today). No change to auth, retries, or other request semantics.

Operational considerations

None. Pure client-side header change, no deploy or feature flag needed. Takes effect on the next version bump.

…tected

The Node SDK sends no User-Agent today, so requests fall back to got's
default. Establish mapbox-sdk-js/<version> as the base UA on every request,
and append " agent/<id>" when a coding-agent env indicator is present
(Node only; the allowlist + precedence mirrors mapbox/tilesets-cli's
agent_detect.py). The browser client explicitly filters the user-agent
header back out, since browsers forbid script-set UA via XHR.
@ctufts ctufts added the locationai-team-skills Opened via the location-ai PR creation skill label Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

locationai-team-skills Opened via the location-ai PR creation skill

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant