Skip to content

Honor AI_AGENT and pass raw values through.#1683

Open
renaudhartert-db wants to merge 4 commits into
mainfrom
feat/ai-agent-env-fallback
Open

Honor AI_AGENT and pass raw values through.#1683
renaudhartert-db wants to merge 4 commits into
mainfrom
feat/ai-agent-env-fallback

Conversation

@renaudhartert-db
Copy link
Copy Markdown
Contributor

@renaudhartert-db renaudhartert-db commented May 15, 2026

Why

The Go SDK detects AI coding agents and surfaces them as agent/<name> in the User-Agent. Today the generic fallback (when no proprietary env var fires) only honors the agents.md AGENT=<name> standard. Vercel's @vercel/detect-agent library uses a parallel AI_AGENT=<name> convention that tools in the Vercel ecosystem set instead; we currently miss those.

Separately, the existing fallback coerces any unrecognized value to the literal string "unknown". That buries useful signal: a tool setting AI_AGENT=claude-code_2-1-141_agent ends up as agent/unknown, discarding the very signal (tool name plus version variant) we want to see. Bucketing arbitrary names is an ETL concern, not the SDK's.

Changes

Two behavior changes in useragent/agent.go:

  1. AI_AGENT fallback. Add AI_AGENT=<name> as a secondary fallback after AGENT=<name>. AGENT wins when both are set to non-empty values; empty is treated as unset for both. Explicit product matchers (e.g. CLAUDECODE=1) still always win over both.

  2. Raw passthrough instead of "unknown". Drop the known-product lookup in the fallback. The value is piped through the existing Sanitize() helper (so disallowed chars become - and the User-Agent allowlist [0-9A-Za-z_.+-]+ is satisfied) and capped at 64 chars to keep the header bounded. Known products like cursor or claude-code pass through unchanged because they already satisfy the allowlist.

Same change should land in databricks-sdk-py and databricks-sdk-java; sibling PRs to follow.

Test plan

  • go test ./useragent/... passes
  • gofmt -l useragent/ clean
  • AI_AGENT=<known product> returns the product name
  • AI_AGENT=<unrecognized> returns the raw sanitized value (no longer "unknown")
  • AGENT wins over AI_AGENT when both are non-empty
  • Empty AGENT falls through to AI_AGENT
  • Disallowed chars in AGENT / AI_AGENT are sanitized to -
  • Values longer than 64 chars are truncated
  • Explicit matcher (e.g. CLAUDECODE=1) still wins over both fallbacks

Adds the Vercel @vercel/detect-agent AI_AGENT=<name> env var as a
secondary fallback after the agents.md AGENT=<name> standard. AGENT
wins when both are non-empty; empty is treated as unset for both.

Also changes the fallback behavior to pass the raw value through
(sanitized via Sanitize() and capped at 64 chars) instead of coercing
unrecognized names to the literal "unknown". Bucketing arbitrary
tool names is an ETL concern, not the SDK's; the prior coercion buried
useful telemetry such as versioned variants like
"claude-code_2-1-141_agent" under agent/unknown.
Trim const comment for maxAgentFallbackLen and the agentEnvFallback
function comment to remove duplicated rationale. Drop three test cases
that exercise the same code path as a sibling case (AGENT=claude-code,
AI_AGENT=claude-code, AI_AGENT-unrecognized-passthrough).
@renaudhartert-db renaudhartert-db changed the title useragent: honor AI_AGENT and pass raw fallback values through Honor AI_AGENT and pass raw values through. May 15, 2026
@github-actions
Copy link
Copy Markdown

If integration tests don't run automatically, an authorized user can run them manually by following the instructions below:

Trigger:
go/deco-tests-run/sdk-go

Inputs:

  • PR number: 1683
  • Commit SHA: 035c7d150de291b63fda64bac1f8c9f0a28bb4be

Checks will be approved automatically on success.

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