Skip to content

feat: send x-vapi-client with a run id on every Vapi request - #85

Merged
scott-lowe-vapi merged 1 commit into
mainfrom
feat/x-vapi-client-header
Oct 30, 2026
Merged

scott-lowe-vapi merged 1 commit into
mainfrom
feat/x-vapi-client-header

Conversation

@scott-lowe-vapi

@scott-lowe-vapi scott-lowe-vapi commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Value

V.A.L.U.E. tier: small — a behavior change: every Vapi API request carries one more header. No blast-radius path.

  • Problem: the User-Agent says which gitops command and version made a request, but not which requests belong to the same run. So "how many apply runs per org", "how many requests and writes a run makes" and "which runs failed" have no answer.
  • Who it affects: the Vapi team measuring gitops adoption. Customers see no change in behavior.
  • Pairs with: VapiAI/vapi#25115, which reads this header on the API and records a [client] api request PostHog event per request, with org, route, status and client_run_id. Either PR can merge first: the API falls back to the User-Agent until this ships, and ignores the header until that ships.

What changes

  • src/user-agent.ts adds vapiClientGet(), which builds x-vapi-client: gitops/<version>; command=<command>; run=<run id>[; ci]. Command and CI detection are shared with userAgentGet(), so the two always agree.
  • Run id: a random UUID, pinned in VAPI_GITOPS_RUN_ID by the first process exactly as VAPI_GITOPS_COMMAND is. npm run apply's pull and push share one id. An inherited value the API would reject is replaced.
  • Every Vapi request sends it: the direct fetch calls, plus VapiConnection (sim, check, promote, rollback, the org pin check) via a new vapiClient field. The GitHub status call doesn't get it.
  • Docs: how-it-works.md says what the header contains and that the run id identifies nothing about the user. AGENTS.md adds it to the every-request rule.

Evidence

  • Contract check across the two repos: a header this branch produced, parsed by the API's vapiClientHeaderParse from #25115:
    gitops/1.0.0; command=cli; run=bc14384b-…; ci → {"client":"gitops","version":"1.0.0","command":"cli","runId":"bc14384b-…","ci":true}
  • tests/user-agent-coverage.test.ts now also requires x-vapi-client on every Vapi fetch in src/ (GitHub's excluded). Its api.ts test checks the header arrives at a real local server with command=apply and a UUID run id.
  • tests/user-agent.test.ts pins the format, CI marker, the rejected-run-id case, and that the process pins a UUID. The sim run-create test checks the header arrives too.

Testing plan

  • npm run build and npm test (579 tests) pass.
  • Not covered: a live run against a Vapi org. The header only becomes visible in PostHog once #25115 is deployed.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@scott-lowe-vapi
scott-lowe-vapi marked this pull request as ready for review October 30, 2026 02:13
@scott-lowe-vapi
scott-lowe-vapi merged commit 1e96134 into main Oct 30, 2026
7 checks passed
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