SIGN IN SIGN UP

agent host: route Claude through CAPI's user-discovered Bearer auth (#316695)

* agent host: route Claude through CAPI's user-discovered Bearer auth

Replace CopilotApiService's fictitious /copilot_internal/v2/token mint
flow with what the @github/copilot CLI actually does: discover the
user's CAPI endpoint via GET /copilot_internal/user, then send the
GitHub user token directly as Authorization: Bearer to /v1/messages
and /models.

Empirically verified against github/copilot-agent-runtime@8f7f8d3:

- fetchCopilotUser at src/core/github/gitHubApi.ts:384-401 GETs
  /copilot_internal/user with Bearer <user-token>.
- The response.endpoints.api is fed through capiClient.updateDomains
  and used as the baseURL for the Anthropic SDK
  (src/model/capi/copilot-anthropic-client.ts:155-182).
- The Anthropic SDK is constructed with authToken = <user-token>, so
  /v1/messages also gets Bearer <user-token>.

Net effect for the agent host:

- Claude tests now work with a vanilla `gh auth token` (previously
  required a Copilot-OAuth token captured from VS Code's GitHub auth
  provider).
- Enterprise users (where endpoints.api ->
  api.enterprise.githubcopilot.com) work without any extra config.
- One round-trip removed per cold start (no separate session-token
  mint).

Test changes:

- copilotApiService.test.ts: rename Token Minting -> Endpoint
  Discovery, drop two tests that asserted on server-supplied
  refresh_in/expires_at (no longer applicable), update auth-header
  assertions to expect the user token verbatim.
- claudeRealSdk.integrationTest.ts: drop AGENT_HOST_REAL_SDK_CLAUDE
  opt-in env var (no longer needed) and rewrite the auth section of
  the docstring.

Verified locally:
- copilotApiService unit tests: 82/82 pass.
- Copilot real-SDK integration suite: 12/12 pass.
- Claude real-SDK integration suite (with `gh auth token` only):
  6/6 active pass; 3 pending (worktree, subagents, plan-mode \u2014
  capability-flag-gated, unchanged from previous PR).

* agent host: per-token CAPIClient to avoid endpoint/token race

Address review feedback on #316695: the previous version mutated a
single shared CAPIClient via updateDomains while allowing discovery
for different GitHub tokens to run concurrently. If token A discovered
endpoint A and token B discovered endpoint B before A's request fired,
A's request could be routed to endpoint B while still carrying A's
bearer token.

Fix by caching a separate CAPIClient per GitHub token (with the same
fixed TTL as before). The token-independent parts (extensionInfo,
machineId/deviceId, userUrl) are still memoized once via
_capiBasePromise so we don't re-derive them on every cache miss.

* agent host: drop dev-stub URLs no longer needed after _mintToken removal

These two URLs were added in #316532 only to keep the now-removed
CopilotApiService._mintToken from hitting 'Failed to parse URL from
undefined' in dev builds. With this PR routing Claude through
/copilot_internal/user (hardcoded), neither URL is referenced by the
agent host any more, so the dev stub no longer needs them.
T
Tyler James Leonhardt committed
712b46f6a58c726756d2aff481a619e34a0ab75f
Parent: eb840b1
Committed by GitHub <noreply@github.com> on 5/16/2026, 12:04:44 AM