Skip to content

feat: add GitHub Copilot as LLM provider with device flow OAuth#323

Open
maros7 wants to merge 13 commits intocampfirein:mainfrom
maros7:feature/github-copilot-provider
Open

feat: add GitHub Copilot as LLM provider with device flow OAuth#323
maros7 wants to merge 13 commits intocampfirein:mainfrom
maros7:feature/github-copilot-provider

Conversation

@maros7
Copy link
Copy Markdown

@maros7 maros7 commented Apr 5, 2026

Summary

  • Problem: ByteRover CLI has no GitHub Copilot provider—users with Copilot subscriptions cannot use Claude, GPT, Gemini, or other models through the Copilot API.
  • Why it matters: GitHub Copilot bundles access to multiple frontier models under a single subscription. Supporting it removes the need for separate API keys per provider.
  • What changed: Added a full github-copilot provider: OAuth device flow authentication, automatic Copilot token refresh, dynamic model listing from the Copilot API, and OpenAI-compatible chat completions for all models (including Claude, Gemini). CLI and TUI connect flows display the device code for the user to enter at github.com/login/device.
  • What did NOT change (scope boundary): No existing providers were modified. No changes to the agent core, tool system, REPL, or transport layer beyond the new device callback mode in shared types/events.

Type of change

  • Bug fix
  • New feature
  • Refactor (no behavior change)
  • Documentation
  • Test
  • Chore (build, dependencies, CI)

Scope (select all touched areas)

  • TUI / REPL
  • Agent / Tools
  • LLM Providers
  • Server / Daemon
  • Shared (constants, types, transport events)
  • CLI Commands (oclif)
  • Hub / Connectors
  • Cloud Sync
  • CI/CD / Infra

Linked issues

Root cause (bug fixes only, otherwise write N/A)

N/A

Test plan

  • Coverage added:
    • Unit test
    • Integration test
    • Manual verification only
  • Test file(s):
    • test/unit/infra/provider-oauth/device-flow.test.ts — 14 tests (device code request, polling, token exchange, error handling)
    • test/unit/infra/llm/providers/github-copilot.test.ts — 18 tests (provider creation, model routing, header injection, error handling)
    • test/unit/infra/http/copilot-model-fetcher.test.ts — 12 tests (model listing, token auth, error handling, empty responses)
    • test/unit/infra/provider-oauth/token-refresh-manager.test.ts — 8 new tests (Copilot token refresh, expiry detection, error wrapping)
    • test/unit/infra/transport/handlers/provider-handler.test.ts — new device flow handler tests
    • test/unit/infra/provider/provider-config-resolver.test.ts — Copilot config resolution tests
    • test/unit/core/domain/entities/provider-registry.test.ts — registry entry tests
    • test/commands/providers/connect.test.ts — CLI connect command device flow tests
  • Key scenario(s) covered:
    • Device flow lifecycle: request code → poll → exchange for Copilot token
    • Polling edge cases: authorization_pending, slow_down (interval backoff), expired_token, access_denied
    • Token refresh: auto-refresh when within 5min of expiry, error wrapping in ProviderTokenExchangeError
    • Model fetcher: dynamic model listing with auth, graceful fallback on errors
    • Provider: OpenAI-compatible format for all models, required Copilot headers (Copilot-Integration-Id, Editor-Version, etc.)
    • Config resolver: Copilot-specific headers and base URL injection

User-visible changes

  • New provider github-copilot available in /providers connect
  • Device flow: CLI/TUI displays a user code and URL (github.com/login/device) instead of opening a browser callback
  • Default model: claude-sonnet-4.6
  • Models listed dynamically from Copilot API (Claude, GPT, Gemini, o-series, etc.)
  • Automatic Copilot token refresh (tokens expire ~30min; refreshed transparently before each request)

Evidence

  • npm run lint: 0 errors (69 pre-existing warnings, none from new code)
  • npm run typecheck: clean
  • npm run build: clean
  • npm test: 4766 passing, 6 pending, 0 failing
  • Coverage: github-copilot.ts 100% lines, device-flow.ts 95% lines, token-refresh-manager.ts 100% lines, copilot.ts 100% lines, CopilotModelFetcher 100% lines — all well above 50% minimum
  • Manual verification: authenticated via device flow, listed models, ran /curate with claude-sonnet-4.6 through Copilot API successfully

Checklist

  • Tests added or updated and passing (npm test)
  • Lint passes (npm run lint)
  • Type check passes (npm run typecheck)
  • Build succeeds (npm run build)
  • Commits follow Conventional Commits format
  • Documentation updated (if applicable)
  • No breaking changes (or clearly documented above)
  • Branch is up to date with main

Risks and mitigations

  • Risk: GitHub changes the Copilot API endpoints, required headers, or token format.
    • Mitigation: All Copilot-specific constants (client ID, URLs, headers, API version) are centralized in src/shared/constants/copilot.ts — a single file to update. Token exchange errors are wrapped in ProviderTokenExchangeError with descriptive messages.
  • Risk: OAuth client ID Iv1.b507a08c87ecfe98 is a well-known public ID (used by VS Code, Goose, gpt4free, etc.) but not officially documented for third-party use.
    • Mitigation: This is the same ID used by dozens of open-source Copilot integrations. If GitHub rotates it, updating the single constant suffices. The device flow itself is a standard OAuth 2.0 grant.

maros7 and others added 13 commits April 4, 2026 20:49
Add Copilot OAuth/API constants (client ID, endpoints, scopes) and extend
shared transport types to support device flow authentication mode with
userCode and verificationUri fields.

Co-authored-by: Claude <noreply@anthropic.com>
Implement GitHub OAuth device flow (RFC 8628) for Copilot authentication
including device code request, access token polling, and Copilot session
token exchange. Includes 12 unit tests covering success paths, error
handling, and polling states.

Co-authored-by: Claude <noreply@anthropic.com>
Add github-copilot entry to PROVIDER_REGISTRY with device callback mode,
priority 8, and default model claude-sonnet-4. Update providerRequiresApiKey
to return false for Copilot. Includes registry test coverage.

Co-authored-by: Claude <noreply@anthropic.com>
Implement CopilotModelFetcher that fetches available models from the
Copilot API using session tokens, register it in the fetcher registry,
and add Copilot case to provider config resolver. Includes model fetcher
and config resolver test coverage.

Co-authored-by: Claude <noreply@anthropic.com>
Extend provider handler to support device flow OAuth: add startDeviceFlow
and awaitDeviceFlow methods, refactor callback flow into awaitCallbackFlow,
and fix return-await in try/catch for proper error propagation. Includes
handler test coverage for all device flow paths.

Co-authored-by: Claude <noreply@anthropic.com>
Extend TokenRefreshManager with doCopilotRefresh method that detects
device callback mode and exchanges the stored GitHub token for a fresh
Copilot session token. Refactor shared error handling into
handleRefreshError. Includes 8 new tests for Copilot refresh paths.

Co-authored-by: Claude <noreply@anthropic.com>
Implement multi-API routing provider that detects model family from ID
and routes to Anthropic SDK for Claude models or OpenAI-compatible SDK
for GPT/Gemini/o-series. Injects Copilot session token as bearer auth.
Includes 18 tests covering all model families and error paths.

Co-authored-by: Claude <noreply@anthropic.com>
Bare AxiosError from exchangeForCopilotToken bypassed isPermanentOAuthError
detection, causing revoked tokens (401/403) to be treated as transient
errors. Wrap axios errors in ProviderTokenExchangeError with status code
to match the pattern used by refresh-token-exchange.ts.

Co-authored-by: Claude <noreply@anthropic.com>
Extract duplicated 'Editor-Version' and 'Copilot-Integration-Id' headers
into COPILOT_REQUEST_HEADERS constant. Replace hardcoded URL strings with
COPILOT_API_BASE_URL in model fetcher. Single source of truth for all
Copilot API configuration values.

Co-authored-by: Claude <noreply@anthropic.com>
…ired headers

Switch from @ai-sdk/anthropic to @ai-sdk/openai-compatible for all models
since the Copilot API only supports OpenAI chat completions format. Add
required Copilot headers (Editor-Plugin-Version, User-Agent, openai-intent,
x-github-api-version) and update default model to claude-sonnet-4.6.
@leehpham leehpham changed the base branch from main to develop April 5, 2026 07:19
@leehpham leehpham changed the base branch from develop to main April 5, 2026 07:22
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.

[FEATURE] Add GitHub Copilot as an LLM Provider (OAuth Device Flow + OpenAI-Compatible API)

1 participant