feat: add support for GitHub Models provider

- Introduced environment variable CLAUDE_CODE_USE_GITHUB to enable GitHub Models.
- Added checks for GITHUB_TOKEN or GH_TOKEN for authentication.
- Updated base URL handling to include GitHub Models default.
- Enhanced provider detection and error handling for GitHub Models.
- Updated relevant functions and components to accommodate the new provider.
This commit is contained in:
Rithul Kamesh
2026-04-02 11:25:28 +05:30
parent e54c39e3cb
commit 25c5987276
24 changed files with 1069 additions and 42 deletions

View File

@@ -2,8 +2,12 @@ import { existsSync, readFileSync } from 'node:fs'
import { homedir } from 'node:os'
import { join } from 'node:path'
import { isEnvTruthy } from '../../utils/envUtils.js'
export const DEFAULT_OPENAI_BASE_URL = 'https://api.openai.com/v1'
export const DEFAULT_CODEX_BASE_URL = 'https://chatgpt.com/backend-api/codex'
/** Default GitHub Models API model when user selects copilot / github:copilot */
export const DEFAULT_GITHUB_MODELS_API_MODEL = 'openai/gpt-4.1'
const CODEX_ALIAS_MODELS: Record<
string,
@@ -171,6 +175,20 @@ export function isCodexBaseUrl(baseUrl: string | undefined): boolean {
}
}
/**
* Normalize user model string for GitHub Models inference (models.github.ai).
* Mirrors runtime devsper `github._normalize_model_id`.
*/
export function normalizeGithubModelsApiModel(requestedModel: string): string {
const noQuery = requestedModel.split('?', 1)[0] ?? requestedModel
const segment =
noQuery.includes(':') ? noQuery.split(':', 2)[1]!.trim() : noQuery.trim()
if (!segment || segment.toLowerCase() === 'copilot') {
return DEFAULT_GITHUB_MODELS_API_MODEL
}
return segment
}
export function resolveProviderRequest(options?: {
model?: string
baseUrl?: string
@@ -192,10 +210,16 @@ export function resolveProviderRequest(options?: {
? 'codex_responses'
: 'chat_completions'
const resolvedModel =
transport === 'chat_completions' &&
isEnvTruthy(process.env.CLAUDE_CODE_USE_GITHUB)
? normalizeGithubModelsApiModel(requestedModel)
: descriptor.baseModel
return {
transport,
requestedModel,
resolvedModel: descriptor.baseModel,
resolvedModel,
baseUrl:
(rawBaseUrl ??
(transport === 'codex_responses'