Skip to content

feat: add agent source tracking to user-agent header#280

Merged
TimPietruskyRunPod merged 4 commits into
mainfrom
zeke/con-85-add-agent-source-tracking-to-cli
Jun 17, 2026
Merged

feat: add agent source tracking to user-agent header#280
TimPietruskyRunPod merged 4 commits into
mainfrom
zeke/con-85-add-agent-source-tracking-to-cli

Conversation

@KAJdev

@KAJdev KAJdev commented May 26, 2026

Copy link
Copy Markdown
Contributor

Appends coding agent source tags to the User-Agent header on all outgoing API requests when the corresponding environment variable is set (e.g. CLAUDECODE=1 adds (via claude-code)). Covers both the REST client and GraphQL client paths.

CON-85

@KAJdev KAJdev requested review from TimPietruskyRunPod and brosenpod and removed request for TimPietruskyRunPod May 26, 2026 18:39
KAJdev and others added 2 commits June 16, 2026 17:06
Generalize agent source tracking beyond Claude Code. Add an
internal/agent package mirroring Hugging Face's public agent-harnesses
registry, detecting ~20 harnesses (Claude Code, Codex, Cursor, Gemini
CLI, Copilot, opencode, and more) plus the standard AI_AGENT/AGENT
fallback, with the same first-match priority ordering.

Both the REST client and the legacy GraphQL query path now share the
single agent.Detect() helper, removing the duplicated inline CLAUDECODE
checks so behavior can't drift.

CON-85
@TimPietruskyRunPod TimPietruskyRunPod force-pushed the zeke/con-85-add-agent-source-tracking-to-cli branch from bb84917 to bb15158 Compare June 16, 2026 15:17

@TimPietruskyRunPod TimPietruskyRunPod left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-tested feature and verified live against production across the REST, GraphQL, and legacy paths — every path emits the (via <agent>) tag and the API accepts it. Rebased onto main is green (go build/vet/test ./...).

Requesting changes on two points before merge, both small:

  1. Bare AGENT fallback risks false attribution (medium) — it's a widely-used variable, so unrelated environments will silently tag traffic with arbitrary strings and pollute the very analytics this feature produces.
  2. Env value flows unsanitized into the User-Agent (low) — not injectable (Go rejects CRLF at write time), but spaces/junk yield a malformed UA. A trim + charset/length clamp would harden it.

Non-blocking nit left inline on the duplicated UA assembly. Happy to fold the fixes in directly if you'd prefer.

Comment thread internal/agent/agent.go Outdated

// standardEnvVars are generic variables any tool can set to identify itself.
// When set, the value is used directly as the agent id.
var standardEnvVars = []string{"AI_AGENT", "AGENT"}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium — drop bare AGENT or namespace it. AGENT is a very common variable (CI runners, tmux/ssh setups, ad-hoc scripts), and its raw value is used directly as the agent id. Unrelated environments will silently tag traffic with arbitrary strings, polluting the analytics this feature exists to produce. AI_AGENT is specific enough to keep; I'd remove bare AGENT or gate it behind a RUNPOD_-namespaced opt-in.

Comment thread internal/agent/agent.go
}
for _, env := range standardEnvVars {
if v := os.Getenv(env); v != "" {
return v

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low — sanitize the fallback value before it reaches the header. This value is concatenated straight into the User-Agent. It isn't header injection (net/http rejects CRLF at write time), but a value with spaces/junk produces a malformed UA. Suggest strings.TrimSpace plus a charset/length clamp (e.g. keep [A-Za-z0-9._-], cap ~64) here before returning.

Comment thread api/query.go Outdated

sanitizedVersion := strings.TrimRight(Version, "\r\n")
userAgent := "RunPod-CLI/" + sanitizedVersion + " (" + runtime.GOOS + "; " + runtime.GOARCH + ")"
if a := agent.Detect(); a != "" {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit (non-blocking) — the UA string is now assembled in two places: internal/api.buildUserAgent() (runpod-cli/...) and here inline (RunPod-CLI/..., different casing, empty version in non-release builds). The package split makes sharing awkward and the casing is pre-existing, so fine to leave — but worth a follow-up to centralize so the (via ...) tag can't drift between paths.

bare AGENT is too common in unrelated environments (ci runners, shell
setups) and would attribute traffic to arbitrary values; only AI_AGENT
is honored now. the standard value is trimmed and clamped to
user-agent-safe chars ([A-Za-z0-9._-], 64 cap) so it can't produce a
malformed header.
@TimPietruskyRunPod

Copy link
Copy Markdown
Member

Pushed 30992cc addressing the two review points:

  • dropped bare AGENT — only AI_AGENT is honored now, so common environments (ci runners, shell setups) can't false-attribute traffic.
  • sanitized the standard value — trimmed + clamped to [A-Za-z0-9._-], 64-rune cap, so an arbitrary env value can't produce a malformed user-agent.

added unit tests for both (bare-AGENT-ignored, injection-stripped, length cap). verified live against production: gpu list etc. still emit (via claude-code), an injected AI_AGENT=$'evil agent\\r\\nX-Injected: 1' lands as (via evilagentX-Injected1), and a bare AGENT produces no tag. the (non-blocking) duplicated UA-assembly nit in api/query.go is left for a follow-up.

both internal/api and the legacy api/query.go built the agent tag
inline, so the format could drift between paths. add agent.Suffix() as
the single source for the fragment; callers keep their own (intentionally
different) cli prefixes.

@TimPietruskyRunPod TimPietruskyRunPod left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all review points addressed in 30992cc (drop bare AGENT + sanitize standard value) and 84c3c92 (centralize the (via ) suffix). build/vet/test green; verified live against production across rest, graphql, and legacy paths. approving.

@TimPietruskyRunPod TimPietruskyRunPod merged commit 2fac5fb into main Jun 17, 2026
1 check passed
@TimPietruskyRunPod TimPietruskyRunPod deleted the zeke/con-85-add-agent-source-tracking-to-cli branch June 17, 2026 08:34
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.

3 participants