Skip to content

Improve GitHub Copilot provider: official OAuth onboarding, Copilot API routing, and test hardening and auto refresh token logic#288

Merged
kevincodex1 merged 29 commits intoGitlawb:mainfrom
Meetpatel006:features/improve-github-copilot
Apr 8, 2026
Merged

Improve GitHub Copilot provider: official OAuth onboarding, Copilot API routing, and test hardening and auto refresh token logic#288
kevincodex1 merged 29 commits intoGitlawb:mainfrom
Meetpatel006:features/improve-github-copilot

Conversation

@Meetpatel006
Copy link
Copy Markdown
Contributor

@Meetpatel006 Meetpatel006 commented Apr 3, 2026

Summary

  • Switched GitHub onboarding to the official Copilot OAuth device flow and added OAuth -> Copilot token exchange before storing credentials.
  • Removed PAT entry from onboarding to standardize on secure OAuth-based sign-in.
  • Updated GitHub provider defaults from models.github.ai to api.githubcopilot.com and aligned request headers with Copilot client expectations.
  • Improved GitHub model normalization and routing so Codex and GPT-5 class models use responses transport when required.
  • Added fallback from chat/completions to responses for copilot newer model.
  • Strengthened startup validation to detect missing, expired, or invalid GitHub tokens with actionable guidance and also its auo refreshing at startup.
  • Expanded and hardened tests (device flow, provider config normalization, and env isolation in provider tests).

Why it changed

  • To make GitHub Copilot integration match real Copilot auth and API behavior.
  • To improve reliability across Copilot-exposed model families and reduce auth/model routing failures.
  • To reduce flaky test behavior caused by environment variable leakage between tests.

Impact

  • GitHub setup is simpler and more consistent with Copilot sign-in.
  • Better compatibility for GPT-5/Codex paths under GitHub mode.
  • Cleaner provider behavior with explicit Copilot base URL and header conventions.
  • More deterministic provider test runs due to improved env cleanup.
  • Onboarding code path is simpler after removing the PAT flow branch.

Testing

  • bun run build
  • bun run smoke
  • focused tests:
    • Ran bun run test:provider
    • Result: 58 passed, 0 failed

Screenshots

Before:
Screenshot 2026-04-03 215445

image

After:
Screenshot 2026-04-03 215606

image

Known limitations

  • PAT onboarding was intentionally removed because when we use its only called older model like gpt 4o and more , and when users use /onboard-github OAuth flow it can access all the model.

@soulcodesmith
Copy link
Copy Markdown

When will it be shipped in OpenClaude? currently it not working on v0.17

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

@Vasanthdev2004 @gnanam1990 can you check it ??

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

Meetpatel006 commented Apr 4, 2026

When will it be shipped in OpenClaude? currently it not working on v0.17

@igsoul now let's see how it goes.

Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

I like the direction here, but I found two blocker-level regressions before I�d be comfortable merging it.

  1. cli.tsx now has a forked copy of provider validation logic that regresses the recently-merged Gemini non-key auth support.
    In src/entrypoints/cli.tsx, the PR reintroduces local getProviderValidationError() / validateProviderEnvOrExit() logic that only accepts GEMINI_API_KEY / GOOGLE_API_KEY. Current main already moved that logic into src/utils/providerValidation.ts, where Gemini access-token and ADC auth are supported. I reproduced this directly on the PR branch: CLAUDE_CODE_USE_GEMINI=1 + GEMINI_ACCESS_TOKEN=dummy-token exits immediately with GEMINI_API_KEY is required when CLAUDE_CODE_USE_GEMINI=1., while the current shared providerValidation helper returns null for the same env.

  2. /onboard-github leaves stale OpenAI-compatible endpoint/key settings behind when switching a user from another OpenAI-compatible provider to GitHub Copilot.
    mergeUserSettingsEnv() in src/commands/onboard-github/onboard-github.tsx sets CLAUDE_CODE_USE_GITHUB=1 and OPENAI_MODEL, and it clears provider-selection flags, but it does not clear OPENAI_BASE_URL or OPENAI_API_KEY. updateSettingsForSource() is a merge, not a replace, so those stale values survive. I reproduced this with a synthetic settings.json containing an old DeepSeek/OpenAI-compatible config: after the onboard merge, the resulting settings still had OPENAI_BASE_URL=https://api.deepseek.com/v1 and OPENAI_API_KEY=sk-old alongside CLAUDE_CODE_USE_GITHUB=1. That means GitHub Copilot onboarding can silently inherit a previous provider base URL/key and route requests to the wrong backend.

The build/smoke checks do pass, so this is not a �PR is broken to compile� issue. But these two behavior regressions are both real enough that I�d fix them before merge.

Vasanthdev2004

This comment was marked as spam.

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

Meetpatel006 commented Apr 4, 2026

@Vasanthdev2004

1. Gemini Non-Key Auth Regression (cli.tsx)

  • Removed duplicated local validation logic from cli.tsx (lines 43–165)

  • Centralized validation using canonical async helpers from providerValidation.ts

  • Moved checkGithubTokenStatus into providerValidation.ts to preserve GitHub token validation

  • Ensured full Gemini authentication support via resolveGeminiCredential():

    • API Key
    • Access Token
    • ADC
    • GEMINI_AUTH_MODE

2. Stale Provider Settings After /onboard-github

Extended cleanup logic in mergeUserSettingsEnv() to remove:

  • OPENAI_BASE_URL
  • OPENAI_API_KEY
  • GEMINI_API_KEY
  • GOOGLE_API_KEY
  • GEMINI_BASE_URL
  • GEMINI_MODEL
  • GEMINI_ACCESS_TOKEN
  • GEMINI_AUTH_MODE

This ensures a clean state when switching providers and prevents stale configuration issues.

Verification

  • bun run test:provider → 75/75 tests passing
  • bun run smoke → Build successful and --version working

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

@Meetpatel006 resolve conflicts

@matheusrodacki
Copy link
Copy Markdown

I'm testing this OpenClaude PR with my GitHub Copilot subscription. A single message to resolve some lint errors cost me 16 premium requests using Claude Sonnet 4.6, and I didn't even let it finish the job. Apparently, each interaction with the OpenClaude agent is charged as a request, which I don't think is worthwhile.

@Meetpatel006 Meetpatel006 force-pushed the features/improve-github-copilot branch from 73b4469 to a29f4cf Compare April 4, 2026 17:35
@Meetpatel006
Copy link
Copy Markdown
Contributor Author

@matheusrodacki, let me check for another; it's working fine, I guess, and @Vasanthdev2004, can you check again??

Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

I like the direction here, but I still see two blocker-level regressions on the current head.

  1. src/entrypoints/cli.tsx still reintroduces a local copy of provider validation logic, and that copy regresses current main's Gemini non-key auth support.

Direct repro from this branch:

  • CLAUDE_CODE_USE_GEMINI=1
  • GEMINI_ACCESS_TOKEN=dummy-token
  • no GEMINI_API_KEY / GOOGLE_API_KEY

The shared src/utils/providerValidation.ts correctly returns null for that env, but the local getProviderValidationError() in cli.tsx returns GEMINI_API_KEY is required when CLAUDE_CODE_USE_GEMINI=1.

So this still rejects a flow that current main already supports.

  1. src/commands/onboard-github/onboard-github.tsx still leaves stale OPENAI_BASE_URL / OPENAI_API_KEY behind when switching from a previous OpenAI-compatible provider setup.

mergeUserSettingsEnv() only clears provider-selection flags, but updateSettingsForSource() merges env maps instead of replacing them. I reproduced that directly with a synthetic prior settings.json containing:

  • OPENAI_BASE_URL=https://api.deepseek.com/v1
  • OPENAI_API_KEY=deepseek-key
  • OPENAI_MODEL=deepseek-chat

After onboarding merge, the resulting env still contains:

  • OPENAI_BASE_URL=https://api.deepseek.com/v1
  • OPENAI_API_KEY=deepseek-key
  • OPENAI_MODEL=github:copilot
  • CLAUDE_CODE_USE_GITHUB=1

So the old OpenAI-compatible endpoint/key survive alongside the new Copilot mode.

I did rerun:

  • bun test ./src/services/github/deviceFlow.test.ts ./src/utils/githubModelsCredentials.refresh.test.ts ./src/services/api/providerConfig.github.test.ts ./src/services/api/withRetry.test.ts ./src/services/api/codexShim.test.ts
  • bun run build
  • bun run smoke

Those pass, but these two regressions are still real enough that I wouldn't merge it yet.

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

@matheusrodacki Bro the issue is like ,

GitHub Billing Model (3rd-Party Coding Agents)

  • User prompt → 1 premium request × model multiplier
  • Agent loop turn (model → tool → result → model) → extra premium requests
  • Claude Sonnet 4.6 → 1× multiplier (paid plans)

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

@Vasanthdev2004

  • Issue 1 → Already fixed in HEAD

    • Bug in commit 85f98af:
      • Local getProviderValidationError() ignored some auth methods
      • Returned misleading GEMINI_API_KEY is required error
    • Fixed in commit a29f4cf:
      • Removed local validation logic from cli.tsx
      • Now uses shared providerValidation module
      • Supports all auth methods via resolveGeminiCredential()
    • Current HEAD (1b6d952):
      • No duplicate validation logic
      • Correct usage confirmed
  • Issue 2 → Fixed

    • onboard-github.tsx now uses proper read-modify-write
    • Prevents stale provider env vars

Vasanthdev2004

This comment was marked as spam.

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

Rechecked the latest head.

Good news first: the two blockers from my earlier review are no longer in the same state.

  • The duplicated Gemini provider validation in src/entrypoints/cli.tsx is fixed now � the branch is using the shared src/utils/providerValidation.ts path again, so the old GEMINI_ACCESS_TOKEN / ADC regression is gone.
  • The saved-settings part of the GitHub onboarding bug is also fixed. I reran the old synthetic DeepSeek-style settings.json repro, and the resulting saved env now correctly reduces to just CLAUDE_CODE_USE_GITHUB=1 + OPENAI_MODEL=github:copilot instead of carrying the old OpenAI-compatible base URL/key forward in the file.

I still see one remaining runtime problem though:

finalize() in src/commands/onboard-github/onboard-github.tsx updates the saved settings, but it only mutates the current process env by setting:

  • CLAUDE_CODE_USE_GITHUB=1
  • OPENAI_MODEL=...

It does not clear stale live-session values such as:

  • CLAUDE_CODE_USE_OPENAI
  • OPENAI_BASE_URL
  • OPENAI_API_KEY

I reproduced that directly with a current-process env that started in a DeepSeek/OpenAI-compatible state. After the branch's current in-process update, getAPIProvider() does return github, but resolveProviderRequest() still uses the stale OPENAI_BASE_URL=https://api.deepseek.com/v1 from the existing process env.

So the saved profile/settings are fixed, but the current session can still stay polluted until restart.

If the intended UX is strictly �restart required after onboarding�, this may be acceptable. But since the flow already hydrates the stored token and calls onChangeAPIKey(), it looks like the goal is to make the current session usable immediately too. In that case I think the current-process env cleanup still needs one more pass before merge.

Copilot AI review requested due to automatic review settings April 5, 2026 05:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the GitHub provider to use official Copilot OAuth device onboarding, exchanges OAuth tokens for Copilot API tokens, and improves Copilot API routing/model handling while hardening provider-related tests and startup credential validation/refresh.

Changes:

  • Switched GitHub onboarding to Copilot’s OAuth device flow + OAuth→Copilot token exchange, and added startup auto-refresh using the stored OAuth token.
  • Updated GitHub defaults/UX to target api.githubcopilot.com, added Copilot-specific headers, and expanded model normalization + routing (including /responses where required).
  • Hardened tests by isolating environment variables and adding coverage for token exchange/refresh and GitHub routing.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/utils/providerValidation.ts Adds GitHub token expiry/format detection and more actionable onboarding error messages.
src/utils/providerFlag.test.ts Improves env isolation to reduce cross-test leakage/flakes.
src/utils/model/modelOptions.ts Adds GitHub provider model picker options sourced from a Copilot model registry.
src/utils/model/model.ts Sets GitHub provider defaults to github:copilot across default-model helpers.
src/utils/model/copilotModels.ts Introduces a hardcoded Copilot model registry used for model selection UI.
src/utils/model/configs.ts Extends model configs to include github and codex provider mappings.
src/utils/githubModelsCredentials.ts Stores OAuth + Copilot tokens, and adds startup auto-refresh via OAuth exchange.
src/utils/githubModelsCredentials.refresh.test.ts Adds tests for GitHub token auto-refresh behavior.
src/services/github/deviceFlow.ts Updates device-flow client/scope and adds OAuth→Copilot token exchange.
src/services/github/deviceFlow.test.ts Adds tests for Copilot token exchange parsing/error handling.
src/services/api/withRetry.test.ts Improves env cleanup/isolation in retry tests.
src/services/api/providerConfig.ts Updates GitHub model normalization and routes certain GitHub models to responses transport.
src/services/api/providerConfig.github.test.ts Expands tests for GitHub normalization and transport routing.
src/services/api/openaiShim.ts Switches GitHub base URL/headers and adds GitHub-specific /responses fallback handling.
src/services/api/codexShim.test.ts Restores env vars after tests to avoid provider cross-contamination.
src/entrypoints/cli.tsx Runs GitHub token refresh on startup before hydration.
src/components/StartupScreen.ts Updates provider display/base URL for “GitHub Copilot”.
src/commands/onboard-github/onboard-github.tsx Removes PAT onboarding, implements OAuth→Copilot exchange, and cleans provider-specific env state.
scripts/system-check.ts Updates GitHub base URL to api.githubcopilot.com.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 333 to 337
const transport: ProviderTransport =
isCodexBaseUrl(rawBaseUrl) || (!rawBaseUrl && isCodexAlias(requestedModel))
isCodexBaseUrl(rawBaseUrl) ||
(!rawBaseUrl && isCodexAlias(requestedModel)) ||
(isGithubMode && shouldUseGithubResponsesApi(githubResolvedModel))
? 'codex_responses'
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

resolveProviderRequest sets transport to codex_responses for GitHub models that need /responses, but the function’s default base URL for codex_responses is DEFAULT_CODEX_BASE_URL when OPENAI_BASE_URL isn’t set. That can route GitHub Copilot GPT‑5/Codex traffic to https://chatgpt.com/backend-api/codex instead of https://api.githubcopilot.com. Suggest adding a GitHub-specific default base URL (or a distinct transport) so GitHub mode uses the Copilot base regardless of transport when no explicit base URL is provided.

Copilot uses AI. Check for mistakes.
Comment on lines +1033 to +1036
if (isGithub && response.status === 400) {
const errorBody = await response.text().catch(() => '')
if (errorBody.includes('/chat/completions') || errorBody.includes('not accessible')) {
const responsesUrl = `${request.baseUrl}/responses`
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

In the GitHub 400-handling path, the response body is read via await response.text() to decide whether to retry via /responses, but if the fallback condition isn’t met the code later calls response.text() again when building the generic APIError. Since the body stream can only be consumed once, this can result in empty/incorrect error messages for GitHub 400s. Consider reading the body once (or using response.clone()) and reusing the same string for both the fallback check and the final error construction.

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +22
type GithubTokenStatus = 'valid' | 'expired' | 'invalid_format'

function checkGithubTokenStatus(token: string): GithubTokenStatus {
const expMatch = token.match(/exp=(\d+)/)
if (expMatch) {
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

checkGithubTokenStatus is duplicated here and in src/utils/githubModelsCredentials.ts. Keeping two copies of token-parsing logic increases the chance they drift (e.g., if Copilot token formats change). Consider extracting this into a shared utility (e.g., src/utils/githubToken.ts) and reusing it in both validation and refresh logic.

Copilot uses AI. Check for mistakes.
Comment on lines 332 to +336
// @[MODEL LAUNCH]: Update the model picker lists below to include/reorder options for the new model.
// Each user tier (ant, Max/Team Premium, Pro/Team Standard/Enterprise, PAYG 1P, PAYG 3P) has its own list.

import { getAllCopilotModels } from './copilotModels.js'

Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

There’s a new static import (getAllCopilotModels) added mid-file. While valid ESM, this file already has a large import block at the top (and a Biome ignore for import ordering), so leaving imports scattered makes the module harder to scan and can complicate tooling. Consider moving this import into the top import section with the others.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 5, 2026 06:09
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/services/api/openaiShim.ts:1106

  • In the GitHub 400-error handling path, the response body is consumed via await response.text() inside the /chat/completions fallback block, and then await response.text() is called again later when building the thrown APIError. Since a Response body can only be read once, the second read will likely be empty, losing the original error details when the fallback condition does not match.

Suggested fix: read the body once and reuse it for both the fallback check and the error construction (or clone the Response before reading).

      // If GitHub Copilot returns error about /chat/completions,
      // try the /responses endpoint (needed for GPT-5+ models)
      if (isGithub && response.status === 400) {
        const errorBody = await response.text().catch(() => '')
        if (errorBody.includes('/chat/completions') || errorBody.includes('not accessible')) {
          const responsesUrl = `${request.baseUrl}/responses`
          const responsesBody: Record<string, unknown> = {
            model: request.resolvedModel,
            input: convertAnthropicMessagesToResponsesInput(
              params.messages as Array<{
                role?: string
                message?: { role?: string; content?: unknown }
                content?: unknown
              }>,
            ),
            stream: params.stream ?? false,
          }

          if (!Array.isArray(responsesBody.input) || responsesBody.input.length === 0) {
            responsesBody.input = [
              {
                type: 'message',
                role: 'user',
                content: [{ type: 'input_text', text: '' }],
              },
            ]
          }

          const systemText = convertSystemPrompt(params.system)
          if (systemText) {
            responsesBody.instructions = systemText
          }

          if (body.max_tokens !== undefined) {
            responsesBody.max_output_tokens = body.max_tokens
          }

          if (params.tools && params.tools.length > 0) {
            const convertedTools = convertToolsToResponsesTools(
              params.tools as Array<{
                name?: string
                description?: string
                input_schema?: Record<string, unknown>
              }>,
            )
            if (convertedTools.length > 0) {
              responsesBody.tools = convertedTools
            }
          }

          const responsesResponse = await fetch(responsesUrl, {
            method: 'POST',
            headers,
            body: JSON.stringify(responsesBody),
            signal: options?.signal,
          })
          if (responsesResponse.ok) {
            return responsesResponse
          }
          const responsesErrorBody = await responsesResponse.text().catch(() => 'unknown error')
          let responsesErrorResponse: object | undefined
          try { responsesErrorResponse = JSON.parse(responsesErrorBody) } catch { /* raw text */ }
          throw APIError.generate(
            responsesResponse.status,
            responsesErrorResponse,
            `OpenAI API error ${responsesResponse.status}: ${responsesErrorBody}`,
            responsesResponse.headers as unknown as Record<string, string>,
          )
        }
      }
      const errorBody = await response.text().catch(() => 'unknown error')
      const rateHint =
        isGithub && response.status === 429 ? formatRetryAfterHint(response) : ''
      let errorResponse: object | undefined
      try { errorResponse = JSON.parse(errorBody) } catch { /* raw text */ }
      throw APIError.generate(

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/services/api/providerConfig.ts Outdated
Comment on lines 325 to 343
const githubResolvedModel = isGithubMode
? normalizeGithubModelsApiModel(requestedModel)
: requestedModel
// Use Codex transport only when:
// - the base URL is explicitly the Codex endpoint, OR
// - the model is a Codex alias AND no custom base URL has been set
// A custom OPENAI_BASE_URL (e.g. Azure, OpenRouter) always wins over
// model-name-based Codex detection to prevent auth failures (#200, #203).
const transport: ProviderTransport =
isCodexBaseUrl(rawBaseUrl) || (!rawBaseUrl && isCodexAlias(requestedModel))
isCodexBaseUrl(rawBaseUrl) ||
(!rawBaseUrl && isCodexAlias(requestedModel)) ||
(isGithubMode && shouldUseGithubResponsesApi(githubResolvedModel))
? 'codex_responses'
: 'chat_completions'

const resolvedModel =
transport === 'chat_completions' &&
isEnvTruthy(process.env.CLAUDE_CODE_USE_GITHUB)
? normalizeGithubModelsApiModel(requestedModel)
: descriptor.baseModel
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

In GitHub mode, resolvedModel is computed from normalizeGithubModelsApiModel(requestedModel) and ignores descriptor.baseModel. This breaks Codex aliases (e.g. codexplan), where parseModelDescriptor resolves the base model to gpt-5.4, but resolvedModel will remain codexplan and be sent to the Copilot API.

Suggested fix: base resolvedModel on descriptor.baseModel (and then apply GitHub normalization to that value), rather than on requestedModel unconditionally in GitHub mode. Adding a regression test for a Codex alias under CLAUDE_CODE_USE_GITHUB=1 would help prevent this from reoccurring.

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +47
type GithubTokenStatus = 'valid' | 'expired' | 'invalid_format'

function checkGithubTokenStatus(token: string): GithubTokenStatus {
const expMatch = token.match(/exp=(\d+)/)
if (expMatch) {
const expSeconds = Number(expMatch[1])
if (!Number.isNaN(expSeconds)) {
return Date.now() >= expSeconds * 1000 ? 'expired' : 'valid'
}
}

const parts = token.split('.')
const looksLikeJwt =
parts.length === 3 && parts.every(part => /^[A-Za-z0-9_-]+$/.test(part))
if (looksLikeJwt) {
try {
const normalized = parts[1].replace(/-/g, '+').replace(/_/g, '/')
const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4)
const json = Buffer.from(padded, 'base64').toString('utf8')
const parsed = JSON.parse(json)
if (parsed && typeof parsed === 'object' && parsed.exp) {
return Date.now() >= (parsed.exp as number) * 1000 ? 'expired' : 'valid'
}
} catch {
return 'invalid_format'
}
}

return 'invalid_format'
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

checkGithubTokenStatus() is duplicated here and in src/utils/githubModelsCredentials.ts. Since both functions gate authentication/refresh behavior, this duplication risks the two drifting over time (leading to inconsistent validation vs refresh decisions).

Suggested fix: extract this token-parsing/expiry logic into a shared utility and import it from both places.

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +41
type GithubTokenStatus = 'valid' | 'expired' | 'invalid_format'

function checkGithubTokenStatus(token: string): GithubTokenStatus {
const expMatch = token.match(/exp=(\d+)/)
if (expMatch) {
const expSeconds = Number(expMatch[1])
if (!Number.isNaN(expSeconds)) {
return Date.now() >= expSeconds * 1000 ? 'expired' : 'valid'
}
}

const parts = token.split('.')
const looksLikeJwt =
parts.length === 3 && parts.every(part => /^[A-Za-z0-9_-]+$/.test(part))
if (looksLikeJwt) {
try {
const normalized = parts[1].replace(/-/g, '+').replace(/_/g, '/')
const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4)
const json = Buffer.from(padded, 'base64').toString('utf8')
const parsed = JSON.parse(json)
if (parsed && typeof parsed === 'object' && parsed.exp) {
return Date.now() >= (parsed.exp as number) * 1000 ? 'expired' : 'valid'
}
} catch {
return 'invalid_format'
}
}

return 'invalid_format'
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

checkGithubTokenStatus() is duplicated here and in src/utils/providerValidation.ts. Because this logic determines whether the startup refresh runs, keeping two separate implementations increases the risk of inconsistent behavior.

Suggested fix: move this helper to a shared utility (e.g. under src/utils/github/ or similar) and reuse it in both modules.

Copilot uses AI. Check for mistakes.
@Meetpatel006
Copy link
Copy Markdown
Contributor Author

@Vasanthdev2004 ,

Fix Applied (lines 99–103)

  • Cleared all PROVIDER_SPECIFIC_KEYS from process.env
  • Set clean vars:
    • CLAUDE_CODE_USE_GITHUB=1
    • OPENAI_MODEL=github:copilot
  • resolveProviderRequest() now:
    • Sees no stale base URL
    • Routes correctly to GitHub Copilot

Test Fix

  • isolate GitHub/Gemini credential tests with fresh module imports and explicit non-bare env setup to prevent cross-test mock/cache leaks

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

@Meetpatel006 checking now

Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

Rechecked the latest head 652e77e8e5f05d1877bc85842bfa28de15012d72.

Good news first:

  • The earlier duplicated Gemini validation issue in src/entrypoints/cli.tsx is fixed.
  • The onboarding path in src/commands/onboard-github/onboard-github.tsx now clears stale provider env in both saved settings and the live process env.

I still can't approve this head because I can reproduce three blocker-level problems:

  1. GitHub mode still breaks Codex aliases.
    In src/services/api/providerConfig.ts:340, resolvedModel is derived from normalizeGithubModelsApiModel(requestedModel) in GitHub mode, which skips descriptor.baseModel. On this head, an actual createOpenAIShimClient() repro with CLAUDE_CODE_USE_GITHUB=1 sends POST https://api.githubcopilot.com/responses with model:codexplan instead of the resolved gpt-5.4. That sends an alias the Copilot API does not understand.

  2. scripts/system-check.ts still crashes in GitHub mode.
    scripts/system-check.ts:160 and scripts/system-check.ts:438 still reference GITHUB_MODELS_DEFAULT_BASE, but the file now defines GITHUB_COPILOT_BASE. Running bun ./scripts/system-check.ts --json with CLAUDE_CODE_USE_GITHUB=1 throws ReferenceError: GITHUB_MODELS_DEFAULT_BASE is not defined.

  3. OpenAI Haiku defaults regressed in an unrelated code path.
    src/utils/model/model.ts:184 now returns gpt-4o for getDefaultHaikuModel() when the active provider is OpenAI. Current main still returns gpt-4o-mini. I reproduced that directly on this head by setting CLAUDE_CODE_USE_OPENAI=1 and calling getDefaultHaikuModel(), which now prints gpt-4o. That's a real cost/latency regression outside the GitHub feature.

Focused verification I reran on this head:

  • bun test ./src/services/api/providerConfig.github.test.ts ./src/services/api/codexShim.test.ts ./src/services/github/deviceFlow.test.ts ./src/utils/githubModelsCredentials.refresh.test.ts ./src/utils/providerFlag.test.ts -> 53 pass
  • bun run build -> success

So build/tests are green, but the current head still has real behavior regressions. I wouldn't merge until those are fixed.

Comment thread src/services/api/providerConfig.ts Outdated
const resolvedModel =
transport === 'chat_completions' &&
isEnvTruthy(process.env.CLAUDE_CODE_USE_GITHUB)
? normalizeGithubModelsApiModel(requestedModel)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This GitHub-specific branch bypasses the normal alias resolution path. On the current head, with CLAUDE_CODE_USE_GITHUB=1, an actual createOpenAIShimClient() repro posts model: \codexplan\ to /responses here instead of the expanded gpt-5.4. We still need GitHub normalization, but the request model needs to come from the parsed descriptor so Codex aliases are resolved before sending.

Comment thread src/utils/model/model.ts Outdated
}
// OpenAI provider
if (getAPIProvider() === 'openai') {
return process.env.OPENAI_MODEL || 'gpt-4o'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This changes the OpenAI Haiku fallback from gpt-4o-mini on main to gpt-4o. I reproduced that directly on this head by setting CLAUDE_CODE_USE_OPENAI=1 and calling getDefaultHaikuModel(), which now returns gpt-4o. That looks like an unrelated cost/latency regression from the GitHub work.

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

Meetpatel006 commented Apr 7, 2026

Summary of Fixes

1. Stale OPENAI_API_BASE Not Cleared During Onboarding

  • Added OPENAI_API_BASE to PROVIDER_SPECIFIC_KEYS in onboard-github.tsx
  • Ensures stale OpenAI routing configuration is cleared when switching providers

2. Incorrect Routing for GitHub GPT-5 / Codex Models

  • providerConfig.ts

    • Updated default base URL for GitHub Copilot (codex_responses transport)
    • Changed from DEFAULT_CODEX_BASE_URL (chatgpt.com) → GITHUB_COPILOT_BASE_URL (api.githubcopilot.com)
  • openaiShim.ts

    • Updated _doRequest() to consistently use GitHub Copilot authentication for all GitHub-mode requests using codex_responses

3. providerOverride.apiKey Ignored in GitHub Requests

  • Updated _doRequest() logic:

    • Now prioritizes this.providerOverride?.apiKey
    • Falls back to process.env.OPENAI_API_KEY only if override is not provided

4. GitHub Model Picker Missing Copilot Models

  • modelOptions.ts

    • Updated getModelOptionsBase() to return full model registry (19 Copilot models) instead of only 2
  • Updated tests to expect 19+ models

5. Test Isolation Improvements

  • Added DEFAULT_GITHUB_DEVICE_SCOPE to mock in githubModelsCredentials.refresh.test.ts
  • Introduced beforeEach() with mock.restore() to ensure proper test cleanup

6. Removed PAT References

  • Updated:

    • deviceFlow.ts error message
    • index.ts description
  • Eliminated outdated Personal Access Token references

Result

  • All tests passing (provider, model, build, smoke)
  • All 19 GitHub Copilot models correctly routed to api.githubcopilot.com

@Vasanthdev2004 yes check this , also i am in window's its works fine for me @igsoul

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

@igsoul, bro, can you check for settings.json and .credentials.json (inside .Claude folder), these two files, and make sure the credentials contain your oauthAccessToken with a prefix like 'ghu' and settings.json looks like

{
  "env": {
    "CLAUDE_CODE_USE_GITHUB": "1",
    "OPENAI_MODEL": "github:copilot"
  },
  "model": "gpt-4.1"
}

Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

Rechecked the latest head 8220dab1d7111fecd8e0f17386d01aafbddaebc8 against current origin/main.

The earlier Copilot-routing and model-picker blockers are fixed on this head, but I still can't approve because the new endpoint split regresses the older GitHub Models API path.

src/services/api/providerConfig.ts:372-376 now only normalizes github:copilot when the base URL resolves to the Copilot host. With CLAUDE_CODE_USE_GITHUB=1 and OPENAI_BASE_URL=https://models.github.ai/inference, the same default model now stays as the literal string github:copilot.

Direct repro on this head:

{
  "transport": "chat_completions",
  "requestedModel": "github:copilot",
  "resolvedModel": "github:copilot",
  "baseUrl": "https://models.github.ai/inference"
}

That is a regression for existing users who still point GitHub mode at models.github.ai/inference and rely on the default model setting. The Models API expects a real model ID like openai/gpt-4.1 / gpt-4o, not github:copilot, so those requests will start failing with 400s from /chat/completions.

The regression comes from the new branch that preserves descriptor.baseModel for non-Copilot GitHub endpoints instead of normalizing the default alias for the Models API path.

What I rechecked on this head:

  • direct code-path review of src/services/api/providerConfig.ts
  • direct runtime repro of resolveProviderRequest() with CLAUDE_CODE_USE_GITHUB=1, OPENAI_BASE_URL=https://models.github.ai/inference, and model=github:copilot
  • source review of src/utils/model/modelOptions.ts, which now does expose the full Copilot model picker for the GitHub provider

I also attempted extra local repro commands after bun install --frozen-lockfile, but this Windows worktree still hit Bun module-resolution failures before those other scripts executed, so I am not using them as review evidence here.

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

@Vasanthdev2004 ,Changes made:

  1. providerConfig.ts:372-379: Now normalizes models for both Copilot AND GitHub Models endpoints (not just Copilot)
    const resolvedModel = isGithubCopilot
    ? normalizeGithubModelsApiModel(descriptor.baseModel)
    : (isGithubModels || isGithubCustom
    ? normalizeGithubModelsApiModel(descriptor.baseModel)
    : descriptor.baseModel)

  2. openaiShim.ts:1201-1206: Added GitHub Models headers when using models endpoint
    } else if (isGithubModels) {
    headers['Accept'] = 'application/vnd.github+json'
    headers['X-GitHub-Api-Version'] = '2022-11-28'
    }

All tests pass (provider, build, smoke). The GitHub Models API now receives properly normalized model IDs like gpt-4o instead of the literal github:copilot alias.

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

@Meetpatel006 check build fail

Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

Rechecked the latest head 6c4e0434556347e50c66744163cd50bd5214254a against current origin/main.

The branch does fix the earlier github:copilot default on models.github.ai, but I still can't approve because three medium regressions remain.

  1. src/entrypoints/cli.tsx:99-124
    GitHub credential refresh/hydration still runs before buildStartupEnvFromProfile() applies a saved provider profile. If the user selected GitHub through the persisted profile rather than shell env vars, refreshGithubModelsTokenIfNeeded() and hydrateGithubModelsTokenFromSecureStorage() both no-op because CLAUDE_CODE_USE_GITHUB is still unset at that point. getProviderValidationError(startupEnv) then sees a GitHub profile with no token and rejects the saved profile.

    Real scenario: user saves GitHub as their default provider, restarts, and the saved profile is ignored unless they also export GitHub env vars manually.

  2. src/commands/onboard-github/onboard-github.tsx:58-67 and src/utils/providerValidation.ts:20-53
    PAT-shaped tokens are still treated as healthy GitHub credentials, but this branch switched the runtime to api.githubcopilot.com, which expects a Copilot token produced by the OAuth exchange, not an old PAT.

    hasExistingGithubModelsLoginToken() returns true for any stored token, and checkGithubTokenStatus() in validation explicitly marks ghp_, ghu_, github_pat_, etc. as valid. That means existing PAT users can hit the "already authorized" fast path, skip the new OAuth flow, and only discover the breakage later when Copilot requests fail.

  3. src/services/api/providerConfig.ts:301-314,372-379
    The latest patch fixes the default alias on models.github.ai, but it still strips provider-qualified model IDs for GitHub Models/custom endpoints.

    Direct repro on this head with CLAUDE_CODE_USE_GITHUB=1 and OPENAI_BASE_URL=https://models.github.ai/inference:

    {
      "defaultAlias": {
        "resolvedModel": "gpt-4o"
      },
      "qualified": {
        "requestedModel": "openai/gpt-4.1",
        "resolvedModel": "gpt-4.1"
      }
    }

    The default alias is now fine, but openai/gpt-4.1 is still rewritten to gpt-4.1. For models.github.ai and similar GitHub-compatible proxies, openai/gpt-4.1 is the valid model ID; stripping the provider prefix will make those requests fail.

What I rechecked on this head:

  • direct code-path review of src/entrypoints/cli.tsx, src/commands/onboard-github/onboard-github.tsx, src/utils/providerValidation.ts, src/utils/githubModelsCredentials.ts, and src/services/api/providerConfig.ts
  • direct runtime repro of resolveProviderRequest() on https://models.github.ai/inference confirming:
    • github:copilot now resolves to gpt-4o
    • openai/gpt-4.1 still resolves incorrectly to gpt-4.1
  • bun install --frozen-lockfile
  • bun run smoke -> success
  • attempted bun run build, but this Windows worktree still hit the recurring Bun module-resolution failures, so I am not using that as PR-specific evidence here

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

@Vasanthdev2004 I don't know about this, because the test failed. In my case, it passed for me. In action the issue is like '1 test failed: '
(fail) Windows clipboard fallback > uses PowerShell instead of clip.exe for local Windows copy [5.00 ms], but for mine it passed.

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

Vasanthdev2004 commented Apr 7, 2026

@Meetpatel006 Regarding the failing CI test — that specific test failure is not caused by this PR's changes.

The failing test is:

\Windows clipboard fallback > uses PowerShell instead of clip.exe for local Windows copy\

This test lives in \src/ink/termio/osc.test.ts, which PR #288 does not touch at all. The test sets \process.platform\ to \win32\ via \Object.defineProperty\ and then verifies that \setClipboard\ calls \powershell. On CI (Linux runners), the mock timing of the async IIFE inside \copyNative\ can race, causing the \powershell\ call not to be observed before the assertion checks. This is a pre-existing flakiness issue in the test's async mock expectations when run on Linux CI — it's not introduced by any change in this branch.

That said, the failing test is still a real CI gate issue and should be addressed (likely by the maintainers adding proper async flushing/await in that test), but it shouldn't block merging this PR.

Separately, I still have three open review blockers on this PR's latest head (\6c4e043) that need to be addressed before I can approve:

  1. \cli.tsx\ credential refresh ordering — GitHub credential refresh/hydration runs before \�uildStartupEnvFromProfile(), so saved GitHub profiles can be silently ignored on restart.
  2. PAT-shaped tokens still treated as healthy in \providerValidation.ts\ and \onboard-github.tsx, even though runtime expects Copilot OAuth-derived tokens.
  3. \providerConfig.ts\ strips provider-qualified IDs like \openai/gpt-4.1\ to \gpt-4.1\ for \models.github.ai\ / custom endpoints, breaking routing.

… model handling for Copilot and GitHub Models
Copilot AI review requested due to automatic review settings April 7, 2026 18:50
@Meetpatel006
Copy link
Copy Markdown
Contributor Author

Summary of Fixes

This PR resolves multiple issues related to GitHub provider integration, API routing, and configuration handling.

Key Fixes

1. Stale OpenAI Config Cleanup

  • Added OPENAI_API_BASE to provider-specific keys
  • Ensures stale routing config is cleared during provider switching

File:

  • src/commands/onboard-github/onboard-github.tsx

2. GitHub Credential Hydration Timing

  • Ensured configs are enabled before reading environment variables
  • Applied settings.env before profile-based env construction
  • Moved credential hydration after profile application

File:

  • src/entrypoints/cli.tsx

3. API Routing: Copilot vs GitHub Models

  • Introduced:
    • normalizeGithubCopilotModel()
    • normalizeGithubModelsApiModel()
  • Added getGithubEndpointType() for endpoint detection

File:

  • src/services/api/providerConfig.ts

4. API Key Override Handling

  • _doRequest() now prioritizes providerOverride.apiKey
  • Falls back to global API key only if override is missing

File:

  • src/services/api/openaiShim.ts

5. GitHub Models API Headers

  • Added required headers:
    • Accept
    • X-GitHub-Api-Version

File:

  • src/services/api/openaiShim.ts

6. PAT Token Handling

  • Personal Access Tokens are now treated as expired
  • Forces OAuth re-authentication

Files:

  • src/utils/providerValidation.ts
  • src/commands/onboard-github/onboard-github.tsx

7. Model Display Names

  • Added github:copilot mapping → displays as "GPT-4o"
  • Updated mapping for all 19 Copilot models

File:

  • src/utils/model/model.ts

8. Model Picker Updates

  • Updated model options to include full Copilot model registry

File:

  • src/utils/model/modelOptions.ts

9. Test Updates

  • Updated provider config tests for new normalization logic
  • Added missing mocks for GitHub device scope

Result

  • No stale configuration leakage during provider switching
  • Correct API routing across GitHub endpoints
  • Proper API key override behavior
  • Full visibility of Copilot models
  • Stable and consistent test suite

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (2)

src/utils/providerFlag.test.ts:35

  • This test file now has two beforeEach() blocks that both delete the same env keys (ENV_KEYS vs RESET_KEYS, which are identical). This redundancy makes the setup harder to reason about and the RESET_KEYS constant appears unnecessary. Consider consolidating to a single list + single beforeEach to snapshot/delete, then restore in afterEach.
const RESET_KEYS = [
  'CLAUDE_CODE_USE_OPENAI',
  'CLAUDE_CODE_USE_GEMINI',
  'CLAUDE_CODE_USE_GITHUB',
  'CLAUDE_CODE_USE_BEDROCK',
  'CLAUDE_CODE_USE_VERTEX',

scripts/system-check.ts:164

  • checkGithubEnv() still reports "GitHub Models provider enabled" and claims the default is "github:copilot → openai/gpt-4.1", but this PR switches the default endpoint/model to GitHub Copilot + gpt-4o. Please update these user-facing diagnostics to match the new provider behavior so system-check output remains accurate.
  const baseUrl = process.env.OPENAI_BASE_URL ?? GITHUB_COPILOT_BASE
  results.push(pass('Provider mode', 'GitHub Models provider enabled.'))

  const token = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN
  if (!token?.trim()) {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

? GITHUB_COPILOT_BASE_URL
: (isGithubMode
? GITHUB_COPILOT_BASE_URL
: DEFAULT_OPENAI_BASE_URL))
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

resolveProviderRequest() no longer defaults codex_responses requests to DEFAULT_CODEX_BASE_URL when no base URL is provided. As written, Codex alias models (e.g. codexplan) will resolve to transport=codex_responses but baseUrl will fall back to the OpenAI base URL, which will break Codex backend requests unless the user explicitly sets OPENAI_BASE_URL. Please restore the DEFAULT_CODEX_BASE_URL fallback when transport is codex_responses and GitHub mode is not active (and add/adjust a test to assert baseUrl for codexplan).

Suggested change
: DEFAULT_OPENAI_BASE_URL))
: (transport === 'codex_responses'
? DEFAULT_CODEX_BASE_URL
: DEFAULT_OPENAI_BASE_URL)))

Copilot uses AI. Check for mistakes.
Comment on lines +378 to 385
const githubResolvedModel = isGithubMode
? normalizeGithubModelsApiModel(requestedModel)
: requestedModel

const transport: ProviderTransport =
shouldUseCodexTransport(requestedModel, rawBaseUrl)
shouldUseCodexTransport(requestedModel, rawBaseUrl) ||
(isGithubCopilot && shouldUseGithubResponsesApi(githubResolvedModel))
? 'codex_responses'
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

For GitHub Copilot routing, shouldUseGithubResponsesApi() is evaluated against githubResolvedModel derived from normalizeGithubModelsApiModel(), which intentionally preserves provider-qualified prefixes (e.g. "openai/gpt-5.4"). That means models like "github:openai/gpt-5.4" won’t match the GPT-5 regex and will incorrectly stay on chat_completions even though normalizeGithubCopilotModel() later resolves them to a GPT-5 model. Consider using the Copilot-normalized model ID (prefix stripped) when deciding whether to route to /responses for Copilot endpoints.

Copilot uses AI. Check for mistakes.
Comment thread src/entrypoints/cli.tsx
Comment on lines +105 to 109
// Apply settings.env from user settings (includes GitHub provider settings from /onboard-github)
{
const { applySafeConfigEnvironmentVariables } = await import('../utils/managedEnv.js')
applySafeConfigEnvironmentVariables()
const { hydrateGeminiAccessTokenFromSecureStorage } = await import('../utils/geminiCredentials.js')
hydrateGeminiAccessTokenFromSecureStorage()
const { hydrateGithubModelsTokenFromSecureStorage } = await import('../utils/githubModelsCredentials.js')
hydrateGithubModelsTokenFromSecureStorage()
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

Gemini access-token hydration from secure storage was removed from the CLI startup path, but provider validation runs before createOpenAIShimClient() (which hydrates Gemini). This can cause validateProviderEnvOrExit() to fail for Gemini users who rely on a stored GEMINI_ACCESS_TOKEN. Suggest re-introducing hydrateGeminiAccessTokenFromSecureStorage() after settings/profile env is applied and before validateProviderEnvOrExit().

Copilot uses AI. Check for mistakes.
Comment thread src/utils/providerValidation.ts Outdated
Comment on lines +23 to +25
// PATs are no longer supported - Copilot API requires OAuth-derived tokens
if (GITHUB_PAT_PREFIXES.some(prefix => token.startsWith(prefix))) {
return 'expired'
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

PATs are treated as token status "expired", which leads to the user-facing message "token has expired". Since PATs are no longer supported (not actually expired), this is misleading. Consider introducing a distinct status (e.g. "pat_not_supported") or returning invalid_format and adjusting the error text to explicitly say PATs aren’t supported and /onboard-github is required.

Suggested change
// PATs are no longer supported - Copilot API requires OAuth-derived tokens
if (GITHUB_PAT_PREFIXES.some(prefix => token.startsWith(prefix))) {
return 'expired'
// PATs are no longer supported - Copilot API requires OAuth-derived tokens,
// so classify them as invalid rather than expired.
if (GITHUB_PAT_PREFIXES.some(prefix => token.startsWith(prefix))) {
return 'invalid_format'

Copilot uses AI. Check for mistakes.
Comment thread src/utils/model/model.ts Outdated
Comment on lines 263 to 267
// GitHub provider (legacy duplicate check - already handled above)
if (getAPIProvider() === 'github') {
return process.env.OPENAI_MODEL || 'github:copilot'
const settings = getSettings_DEPRECATED() || {}
return settings.model || process.env.OPENAI_MODEL || 'github:copilot'
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

getDefaultMainLoopModelSetting() contains a duplicate getAPIProvider()==='github' branch later in the function that is now unreachable because GitHub is handled at the top. Please remove the duplicate block to avoid confusion and reduce the chance of future changes diverging between the two branches.

Copilot uses AI. Check for mistakes.
Comment on lines +216 to +218
}
process.env.CLAUDE_CODE_USE_GITHUB = '1'
process.env.OPENAI_MODEL = model.trim() || DEFAULT_MODEL
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

finalize() clears various provider env vars but does not clear or overwrite an existing GITHUB_TOKEN/GH_TOKEN in the current session before calling hydrateGithubModelsTokenFromSecureStorage(). If the user is re-authing (or had a stale env token set), hydrate() will early-return and the session can keep using the old token until restart. Consider explicitly setting process.env.GITHUB_TOKEN to the newly issued Copilot token (or deleting any existing GH_TOKEN/GITHUB_TOKEN before hydrating) so onboarding takes effect immediately.

Suggested change
}
process.env.CLAUDE_CODE_USE_GITHUB = '1'
process.env.OPENAI_MODEL = model.trim() || DEFAULT_MODEL
}
// Ensure any stale GitHub token env vars from the current session do
// not prevent the newly saved token from taking effect immediately.
delete process.env.GH_TOKEN
delete process.env.GITHUB_TOKEN
process.env.CLAUDE_CODE_USE_GITHUB = '1'
process.env.OPENAI_MODEL = model.trim() || DEFAULT_MODEL
process.env.GITHUB_TOKEN = token

Copilot uses AI. Check for mistakes.
@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

Vasanthdev2004 commented Apr 7, 2026

@Meetpatel006 This PR has been through many review rounds. Instead of another CHANGES_REQUESTED, here are the specific code issues that need fixing to merge, with concrete suggestions.


1. Dead code: duplicate GitHub branch in \getDefaultMainLoopModelSetting\

\\ s
// src/utils/model/model.ts lines 250-254
if (getAPIProvider() === 'github') {
const settings = getSettings_DEPRECATED() || {}
return settings.model || process.env.OPENAI_MODEL || 'github:copilot'
}
// ... other branches ...
// Line 263-267 — UNREACHABLE, already returned above
if (getAPIProvider() === 'github') {
const settings = getSettings_DEPRECATED() || {}
return settings.model || process.env.OPENAI_MODEL || 'github:copilot'
}
\\

The second \if (getAPIProvider() === 'github')\ block on line 263 is dead code — the first block on line 250 already returns for the \github\ provider. Delete lines 263-267.


2. PAT tokens treated as \expired\ breaks existing users

\src/utils/providerValidation.ts:24:
\\ s
if (GITHUB_PAT_PREFIXES.some(prefix => token.startsWith(prefix))) {
return 'expired'
}
\\

Any user with a Classic PAT (\ghp_), Fine-grained PAT (\github_pat_), or OAuth App token (\gho_, \ghu_, \ghs_, \ghr_) gets told their token is expired and directed to /onboard-github. But:

  • Classic PATs (\ghp_*) still work with \models.github.ai\ (they support PAT auth)
  • Fine-grained PATs (\github_pat_*) also work with \models.github.ai\

This is a breaking change for existing users using PATs with \models.github.ai. The fix depends on intent:

  • If Copilot API (\�pi.githubcopilot.com) requires OAuth tokens only → validate PATs as expired only when the endpoint is Copilot, not for \models.github.ai\
  • If PATs should work everywhere → return 'valid'\ for known PAT prefixes instead of 'expired'\

Suggested fix:
\\ s
function checkGithubTokenStatus(token: string, endpoint: 'copilot' | 'models' | 'custom' = 'copilot'): GithubTokenStatus {
if (GITHUB_PAT_PREFIXES.some(prefix => token.startsWith(prefix))) {
// PATs work with GitHub Models but not with Copilot API
if (endpoint === 'copilot') {
return 'expired'
}
return 'valid'
}
// ... rest unchanged
}
\\

And wire \endpoint\ from \getGithubEndpointType()\ at the call site in \getProviderValidationError.


3. Startup credential ordering in \cli.tsx\

The sequence in \src/entrypoints/cli.tsx\ is:

  1. \hydrateGithubModelsTokenFromSecureStorage()\ (reads stored OAuth token)
  2. \�uildStartupEnvFromProfile()\ (applies saved profile, which may set \CLAUDE_CODE_USE_GITHUB=1\ plus a different endpoint)

If the user's saved profile uses GitHub Models with a custom endpoint, step 1 may set \GITHUB_TOKEN\ from the stored OAuth token, and then step 2 may overwrite \OPENAI_BASE_URL\ but not clear the stale OAuth token. On restart, the stale OAuth token from step 1 can take precedence over the profile's intended configuration.

Suggested fix: call \�uildStartupEnvFromProfile()\ before the hydration steps, or clear \GITHUB_TOKEN/\GH_TOKEN\ inside \�uildStartupEnvFromProfile\ when the profile changes the provider away from GitHub.


4. Redundant .toLowerCase()\ in \getGithubEndpointType\

\src/services/api/providerConfig.ts:341:
\\ s
if (hostname === 'api.githubcopilot.com' || hostname === 'api.githubcopilot.com'.toLowerCase()) {
\\

'api.githubcopilot.com'.toLowerCase()\ is identical to 'api.githubcopilot.com'\ since it's already lowercase. Remove the redundant second condition.


5. CI test failure: Windows clipboard fallback

The failing test (\src/ink/termio/osc.test.ts) is not touched by this PR. It's a pre-existing flaky test that races async IIFE timing on Linux CI. This shouldn't block the PR. Consider adding a skip condition for non-Windows platforms:
\\ s
describe.skip(process.platform === 'win32' ? 'Windows clipboard fallback' : 'Windows clipboard fallback (skipped on non-Windows)', () => {
\\

Or convert the test to use proper async awaiting.


@Meetpatel006
Copy link
Copy Markdown
Contributor Author

Key Fixes

1. Dead Code Removal

  • Removed duplicate GitHub branch in getDefaultMainLoopModelSetting() (lines 263-267)

2. PAT Token Handling for GitHub Models

  • Updated checkGithubTokenStatus() to accept endpoint type
  • PAT tokens are treated as expired only for Copilot API (api.githubcopilot.com)
  • PAT tokens remain valid for:
    • GitHub Models (models.github.ai)
    • Custom endpoints
  • Connected endpoint detection using getGithubEndpointType() in validation flow

3. Redundant Logic Cleanup

  • Removed unnecessary .toLowerCase() in hostname comparison

4. Credential Initialization Order

  • Verified correct execution order:
    • settings.env
    • profile
    • credential hydration

Result

  • Cleaner codebase with no redundant branches
  • Correct token validation behavior across GitHub endpoints
  • Improved maintainability in provider validation logic
  • All tests passing including build, smoke, and provider tests

Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

Re-reviewed the latest head 6a9f89d against current origin/main.

All three blockers from the previous review are now fixed:

  1. Dead code in getDefaultMainLoopModelSetting — removed ✅
  2. PAT tokens now endpoint-aware (expired for copilot, valid for models/custom) ✅
  3. Startup credential ordering — hydrateGithubModelsTokenFromSecureStorage and refreshGithubModelsTokenIfNeeded now run after buildStartupEnvFromProfile ✅
  4. Redundant .toLowerCase() removed ✅

One minor note for follow-up (not blocking):

DEFAULT_GITHUB_MODELS_API_MODEL changed from openai/gpt-4.1 to gpt-4o. When github:copilot is used with models.github.ai, this resolves to gpt-4o without a provider prefix. The GitHub Models API does accept unqualified IDs and routes to the default provider, so this works — but if the intent is to maximize compatibility with all GitHub Models features, openai/gpt-4o would be more explicit. Low priority since the Copilot endpoint (the primary target of this PR) uses unqualified IDs.

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

@kevincodex1 one more eyes

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

I fix this patch my EOD and give final call, this

@auriti
Copy link
Copy Markdown
Collaborator

auriti commented Apr 8, 2026

Quick status pass on the latest head (6a9f89d7) from my side:

  • CI is green (smoke-and-tests passing)
  • the earlier registerSkillifySkill() concern no longer appears in the current branch
  • the GitHub token handling now looks endpoint-aware in providerValidation.ts (copilot vs models/custom)
  • the startup ordering issue called out in review also looks addressed: profile env is applied before GitHub credential refresh/hydration runs in cli.tsx

I also ran a focused local pass on the current branch around the GitHub-specific regression areas (providerConfig.github, githubModelsCredentials.refresh, providerFlag, geminiCredentials, and deviceFlow). I didn’t find a new blocker in the latest head.

At this point the branch looks mainly blocked on stale review state rather than failing checks. If anyone still sees an unresolved issue on the current head, please point to the specific file/behavior on 6a9f89d7; otherwise a fresh re-review from the remaining reviewers would probably unblock merge.

@Zartris
Copy link
Copy Markdown
Contributor

Zartris commented Apr 8, 2026

This PR saved my day! Works wonderful!

Copy link
Copy Markdown
Contributor

@kevincodex1 kevincodex1 left a comment

Choose a reason for hiding this comment

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

looks good to me

@kevincodex1 kevincodex1 merged commit ad724dc into Gitlawb:main Apr 8, 2026
1 check passed
ibaaaaal pushed a commit to ibaaaaal/openclaude that referenced this pull request Apr 8, 2026
…PI routing, and test hardening and auto refresh token logic (Gitlawb#288)

* update gitHub copilot API with offical client id and update model configurations

* test: add unit tests for exchangeForCopilotToken and enhance GitHub model normalization

* remove PAT token feature

* test(api): harden provider tests against env leakage

* Added back trimmed github auth token

* added auto refresh logic for auto token along with test

* fix: remove forked provider validation in cli.tsx and clear stale provider env vars in /onboard-github

* refactor: streamline environment variable handling in mergeUserSettingsEnv

* fix: clear stale provider env vars to ensure correct GH routing

* Remove internal-only tooling from the external build (Gitlawb#352)

* Remove internal-only tooling without changing external runtime contracts

This trims the lowest-risk internal-only surfaces first: deleted internal
modules are replaced by build-time no-op stubs, the bundled stuck skill is
removed, and the insights S3 upload path now stays local-only. The privacy
verifier is expanded and the remaining bundled internal Slack/Artifactory
strings are neutralized without broad repo-wide renames.

Constraint: Keep the first PR deletion-heavy and avoid mass rewrites of USER_TYPE, tengu, or claude_code identifiers
Rejected: One-shot DMCA cleanup branch | too much semantic risk for a first PR
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Treat full-repo typecheck as a baseline issue on this upstream snapshot; do not claim this commit introduced the existing non-Phase-A errors without isolating them first
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Not-tested: Full repo typecheck (currently fails on widespread pre-existing upstream errors outside this change set)

* Keep minimal source shims so CI can import Phase A cleanup paths

The first PR removed internal-only source files entirely, but CI provider
and context tests import those modules directly from source rather than
through the build-time no-telemetry stubs. This restores tiny no-op source
shims so tests and local source imports resolve while preserving the same
external runtime behavior.

Constraint: GitHub Actions runs source-level tests in addition to bundled build/privacy checks
Rejected: Revert the entire deletion pass | unnecessary once the import contract is satisfied by small shims
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: For later cleanup phases, treat build-time stubs and source-test imports as separate compatibility surfaces
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (still noisy on this upstream snapshot)

---------

Co-authored-by: anandh8x <test@example.com>

* Reduce internal-only labeling noise in source comments (Gitlawb#355)

This pass rewrites comment-only ANT-ONLY markers to neutral internal-only
language across the source tree without changing runtime strings, flags,
commands, or protocol identifiers. The goal is to lower obvious internal
prose leakage while keeping the diff mechanically safe and easy to review.

Constraint: Phase B is limited to comments/prose only; runtime strings and user-facing labels remain deferred
Rejected: Broad search-and-replace across strings and command descriptions | too risky for a prose-only pass
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Remaining ANT-ONLY hits are mostly runtime/user-facing strings and should be handled separately from comment cleanup
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Neutralize internal Anthropic prose in explanatory comments (Gitlawb#357)

This is a small prose-only follow-up that rewrites clearly internal or
explanatory Anthropic comment language to neutral wording in a handful of
high-confidence files. It avoids runtime strings, flags, command labels,
protocol identifiers, and provider-facing references.

Constraint: Keep this pass narrowly scoped to comments/documentation only
Rejected: Broader Anthropic comment sweep across functional API/protocol references | too ambiguous for a safe prose-only PR
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Leave functional Anthropic references (API behavior, SDKs, URLs, provider labels, protocol docs) for separate reviewed passes
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Neutralize remaining internal-only diagnostic labels (Gitlawb#359)

This pass rewrites a small set of ant-only diagnostic and UI labels to
neutral internal wording while leaving command definitions, flags, and
runtime logic untouched. It focuses on internal debug output, dead UI
branches, and noninteractive headings rather than broader product text.

Constraint: Label cleanup only; do not change command semantics or ant-only logic gates
Rejected: Renaming ant-only command descriptions in main.tsx | broader UX surface better handled in a separate reviewed pass
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Remaining ANT-ONLY hits are mostly command descriptions and intentionally deferred user-facing strings
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Finish eliminating remaining ANT-ONLY source labels (Gitlawb#360)

This extends the label-only cleanup to the remaining internal-only command,
debug, and heading strings so the source tree no longer contains ANT-ONLY
markers. The pass still avoids logic changes and only renames labels shown
in internal or gated surfaces.

Constraint: Update the existing label-cleanup PR without widening scope into behavior changes
Rejected: Leave the last ANT-ONLY strings for a later pass | low-cost cleanup while the branch is already focused on labels
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: The next phase should move off label cleanup and onto a separately scoped logic or rebrand slice
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Stub internal-only recording and model capability helpers (Gitlawb#377)

This follow-up Phase C-lite slice replaces purely internal helper modules
with stable external no-op surfaces and collapses internal elevated error
logging to a no-op. The change removes additional USER_TYPE-gated helper
behavior without touching product-facing runtime flows.

Constraint: Keep this PR limited to isolated helper modules that are already external no-ops in practice
Rejected: Pulling in broader speculation or logging sink changes | less isolated and easier to debate during review
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Continue Phase C with similarly isolated helpers before moving into mixed behavior files
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Remove internal-only bundled skills and mock helpers (Gitlawb#376)

* Remove internal-only bundled skills and mock rate-limit behavior

This takes the next planned Phase C-lite slice by deleting bundled skills
that only ever registered for internal users and replacing the internal
mock rate-limit helper with a stable no-op external stub. The external
build keeps the same behavior while removing a concentrated block of
USER_TYPE-gated dead code.

Constraint: Limit this PR to isolated internal-only helpers and avoid bridge, oauth, or rebrand behavior
Rejected: Broad USER_TYPE cleanup across mixed runtime surfaces | too risky for the next medium-sized PR
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: The next cleanup pass should continue with similarly isolated USER_TYPE helpers before touching main.tsx or protocol-heavy code
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

* Align internal-only helper removal with remaining user guidance

This follow-up fixes the mock billing stub to be a true no-op and removes
stale user-facing references to /verify and /skillify from the same PR.
It also leaves a clearer paper trail for review: the deleted verify skill
was explicitly ant-gated before removal, and the remaining mock helper
callers still resolve to safe no-op returns in the external build.

Constraint: Keep the PR focused on consistency fixes and reviewer-requested evidence, not new cleanup scope
Rejected: Leave stale guidance for a later PR | would make this branch internally inconsistent after skill removal
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When deleting gated features, always sweep user guidance and coordinator prompts in the same pass
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy; changed-file scan still shows only pre-existing tipRegistry errors outside edited lines)

* Clarify generic workflow wording after skill removal

This removes the last generic verification-skill wording that could still
be read as pointing at a deleted bundled command. The guidance now talks
about project workflows rather than a specific bundled verify skill.

Constraint: Keep the follow-up limited to reviewer-facing wording cleanup on the same PR
Rejected: Leave generic wording as-is | still too easy to misread after the explicit /verify references were removed
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When removing bundled commands, scrub both explicit and generic references in the same branch
Tested: bun run build
Tested: bun run smoke
Not-tested: Additional checks unchanged by wording-only follow-up

---------

Co-authored-by: anandh8x <test@example.com>

* test(api): add GEMINI_AUTH_MODE to environment setup in tests

* test: isolate GitHub/Gemini credential tests with fresh module imports and explicit non-bare env setup to prevent cross-test mock/cache leaks

* fix: update GitHub Copilot base URL and model defaults for improved compatibility

* fix: enhance error handling in OpenAI API response processing

* fix: improve error handling for GitHub Copilot API responses and streamline error body consumption

* fix: enhance response handling in OpenAI API shim for better error reporting and support for streaming responses

* feat: enhance GitHub device flow with fresh module import and token validation improvements

* fix: separate Copilot API routing from GitHub Models, clear stale env vars, honor providerOverride.apiKey

* fix: route GitHub GPT-5/Codex to Copilot API, show all Copilot models in picker, clear stale env vars

* fix GitHub Models API regression

* feat: update GitHub authentication to require OAuth tokens, normalize model handling for Copilot and GitHub Models

* fix: update GitHub token validation to support OAuth tokens and improve endpoint type handling

---------

Co-authored-by: Anandan <anandan.8x@gmail.com>
Co-authored-by: anandh8x <test@example.com>
DavidIfebueme pushed a commit to DavidIfebueme/openclaude that referenced this pull request Apr 8, 2026
…PI routing, and test hardening and auto refresh token logic (Gitlawb#288)

* update gitHub copilot API with offical client id and update model configurations

* test: add unit tests for exchangeForCopilotToken and enhance GitHub model normalization

* remove PAT token feature

* test(api): harden provider tests against env leakage

* Added back trimmed github auth token

* added auto refresh logic for auto token along with test

* fix: remove forked provider validation in cli.tsx and clear stale provider env vars in /onboard-github

* refactor: streamline environment variable handling in mergeUserSettingsEnv

* fix: clear stale provider env vars to ensure correct GH routing

* Remove internal-only tooling from the external build (Gitlawb#352)

* Remove internal-only tooling without changing external runtime contracts

This trims the lowest-risk internal-only surfaces first: deleted internal
modules are replaced by build-time no-op stubs, the bundled stuck skill is
removed, and the insights S3 upload path now stays local-only. The privacy
verifier is expanded and the remaining bundled internal Slack/Artifactory
strings are neutralized without broad repo-wide renames.

Constraint: Keep the first PR deletion-heavy and avoid mass rewrites of USER_TYPE, tengu, or claude_code identifiers
Rejected: One-shot DMCA cleanup branch | too much semantic risk for a first PR
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Treat full-repo typecheck as a baseline issue on this upstream snapshot; do not claim this commit introduced the existing non-Phase-A errors without isolating them first
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Not-tested: Full repo typecheck (currently fails on widespread pre-existing upstream errors outside this change set)

* Keep minimal source shims so CI can import Phase A cleanup paths

The first PR removed internal-only source files entirely, but CI provider
and context tests import those modules directly from source rather than
through the build-time no-telemetry stubs. This restores tiny no-op source
shims so tests and local source imports resolve while preserving the same
external runtime behavior.

Constraint: GitHub Actions runs source-level tests in addition to bundled build/privacy checks
Rejected: Revert the entire deletion pass | unnecessary once the import contract is satisfied by small shims
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: For later cleanup phases, treat build-time stubs and source-test imports as separate compatibility surfaces
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (still noisy on this upstream snapshot)

---------

Co-authored-by: anandh8x <test@example.com>

* Reduce internal-only labeling noise in source comments (Gitlawb#355)

This pass rewrites comment-only ANT-ONLY markers to neutral internal-only
language across the source tree without changing runtime strings, flags,
commands, or protocol identifiers. The goal is to lower obvious internal
prose leakage while keeping the diff mechanically safe and easy to review.

Constraint: Phase B is limited to comments/prose only; runtime strings and user-facing labels remain deferred
Rejected: Broad search-and-replace across strings and command descriptions | too risky for a prose-only pass
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Remaining ANT-ONLY hits are mostly runtime/user-facing strings and should be handled separately from comment cleanup
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Neutralize internal Anthropic prose in explanatory comments (Gitlawb#357)

This is a small prose-only follow-up that rewrites clearly internal or
explanatory Anthropic comment language to neutral wording in a handful of
high-confidence files. It avoids runtime strings, flags, command labels,
protocol identifiers, and provider-facing references.

Constraint: Keep this pass narrowly scoped to comments/documentation only
Rejected: Broader Anthropic comment sweep across functional API/protocol references | too ambiguous for a safe prose-only PR
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Leave functional Anthropic references (API behavior, SDKs, URLs, provider labels, protocol docs) for separate reviewed passes
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Neutralize remaining internal-only diagnostic labels (Gitlawb#359)

This pass rewrites a small set of ant-only diagnostic and UI labels to
neutral internal wording while leaving command definitions, flags, and
runtime logic untouched. It focuses on internal debug output, dead UI
branches, and noninteractive headings rather than broader product text.

Constraint: Label cleanup only; do not change command semantics or ant-only logic gates
Rejected: Renaming ant-only command descriptions in main.tsx | broader UX surface better handled in a separate reviewed pass
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Remaining ANT-ONLY hits are mostly command descriptions and intentionally deferred user-facing strings
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Finish eliminating remaining ANT-ONLY source labels (Gitlawb#360)

This extends the label-only cleanup to the remaining internal-only command,
debug, and heading strings so the source tree no longer contains ANT-ONLY
markers. The pass still avoids logic changes and only renames labels shown
in internal or gated surfaces.

Constraint: Update the existing label-cleanup PR without widening scope into behavior changes
Rejected: Leave the last ANT-ONLY strings for a later pass | low-cost cleanup while the branch is already focused on labels
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: The next phase should move off label cleanup and onto a separately scoped logic or rebrand slice
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Stub internal-only recording and model capability helpers (Gitlawb#377)

This follow-up Phase C-lite slice replaces purely internal helper modules
with stable external no-op surfaces and collapses internal elevated error
logging to a no-op. The change removes additional USER_TYPE-gated helper
behavior without touching product-facing runtime flows.

Constraint: Keep this PR limited to isolated helper modules that are already external no-ops in practice
Rejected: Pulling in broader speculation or logging sink changes | less isolated and easier to debate during review
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Continue Phase C with similarly isolated helpers before moving into mixed behavior files
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Remove internal-only bundled skills and mock helpers (Gitlawb#376)

* Remove internal-only bundled skills and mock rate-limit behavior

This takes the next planned Phase C-lite slice by deleting bundled skills
that only ever registered for internal users and replacing the internal
mock rate-limit helper with a stable no-op external stub. The external
build keeps the same behavior while removing a concentrated block of
USER_TYPE-gated dead code.

Constraint: Limit this PR to isolated internal-only helpers and avoid bridge, oauth, or rebrand behavior
Rejected: Broad USER_TYPE cleanup across mixed runtime surfaces | too risky for the next medium-sized PR
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: The next cleanup pass should continue with similarly isolated USER_TYPE helpers before touching main.tsx or protocol-heavy code
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

* Align internal-only helper removal with remaining user guidance

This follow-up fixes the mock billing stub to be a true no-op and removes
stale user-facing references to /verify and /skillify from the same PR.
It also leaves a clearer paper trail for review: the deleted verify skill
was explicitly ant-gated before removal, and the remaining mock helper
callers still resolve to safe no-op returns in the external build.

Constraint: Keep the PR focused on consistency fixes and reviewer-requested evidence, not new cleanup scope
Rejected: Leave stale guidance for a later PR | would make this branch internally inconsistent after skill removal
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When deleting gated features, always sweep user guidance and coordinator prompts in the same pass
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy; changed-file scan still shows only pre-existing tipRegistry errors outside edited lines)

* Clarify generic workflow wording after skill removal

This removes the last generic verification-skill wording that could still
be read as pointing at a deleted bundled command. The guidance now talks
about project workflows rather than a specific bundled verify skill.

Constraint: Keep the follow-up limited to reviewer-facing wording cleanup on the same PR
Rejected: Leave generic wording as-is | still too easy to misread after the explicit /verify references were removed
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When removing bundled commands, scrub both explicit and generic references in the same branch
Tested: bun run build
Tested: bun run smoke
Not-tested: Additional checks unchanged by wording-only follow-up

---------

Co-authored-by: anandh8x <test@example.com>

* test(api): add GEMINI_AUTH_MODE to environment setup in tests

* test: isolate GitHub/Gemini credential tests with fresh module imports and explicit non-bare env setup to prevent cross-test mock/cache leaks

* fix: update GitHub Copilot base URL and model defaults for improved compatibility

* fix: enhance error handling in OpenAI API response processing

* fix: improve error handling for GitHub Copilot API responses and streamline error body consumption

* fix: enhance response handling in OpenAI API shim for better error reporting and support for streaming responses

* feat: enhance GitHub device flow with fresh module import and token validation improvements

* fix: separate Copilot API routing from GitHub Models, clear stale env vars, honor providerOverride.apiKey

* fix: route GitHub GPT-5/Codex to Copilot API, show all Copilot models in picker, clear stale env vars

* fix GitHub Models API regression

* feat: update GitHub authentication to require OAuth tokens, normalize model handling for Copilot and GitHub Models

* fix: update GitHub token validation to support OAuth tokens and improve endpoint type handling

---------

Co-authored-by: Anandan <anandan.8x@gmail.com>
Co-authored-by: anandh8x <test@example.com>
@LoackyBit
Copy link
Copy Markdown

When will it be released? I'm using v0.18 and it doesn't work.

@Meetpatel006
Copy link
Copy Markdown
Contributor Author

Connect to owner, it will be on next version

euxaristia pushed a commit to euxaristia/openclaude that referenced this pull request Apr 13, 2026
…PI routing, and test hardening and auto refresh token logic (Gitlawb#288)

* update gitHub copilot API with offical client id and update model configurations

* test: add unit tests for exchangeForCopilotToken and enhance GitHub model normalization

* remove PAT token feature

* test(api): harden provider tests against env leakage

* Added back trimmed github auth token

* added auto refresh logic for auto token along with test

* fix: remove forked provider validation in cli.tsx and clear stale provider env vars in /onboard-github

* refactor: streamline environment variable handling in mergeUserSettingsEnv

* fix: clear stale provider env vars to ensure correct GH routing

* Remove internal-only tooling from the external build (Gitlawb#352)

* Remove internal-only tooling without changing external runtime contracts

This trims the lowest-risk internal-only surfaces first: deleted internal
modules are replaced by build-time no-op stubs, the bundled stuck skill is
removed, and the insights S3 upload path now stays local-only. The privacy
verifier is expanded and the remaining bundled internal Slack/Artifactory
strings are neutralized without broad repo-wide renames.

Constraint: Keep the first PR deletion-heavy and avoid mass rewrites of USER_TYPE, tengu, or claude_code identifiers
Rejected: One-shot DMCA cleanup branch | too much semantic risk for a first PR
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Treat full-repo typecheck as a baseline issue on this upstream snapshot; do not claim this commit introduced the existing non-Phase-A errors without isolating them first
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Not-tested: Full repo typecheck (currently fails on widespread pre-existing upstream errors outside this change set)

* Keep minimal source shims so CI can import Phase A cleanup paths

The first PR removed internal-only source files entirely, but CI provider
and context tests import those modules directly from source rather than
through the build-time no-telemetry stubs. This restores tiny no-op source
shims so tests and local source imports resolve while preserving the same
external runtime behavior.

Constraint: GitHub Actions runs source-level tests in addition to bundled build/privacy checks
Rejected: Revert the entire deletion pass | unnecessary once the import contract is satisfied by small shims
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: For later cleanup phases, treat build-time stubs and source-test imports as separate compatibility surfaces
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (still noisy on this upstream snapshot)

---------

Co-authored-by: anandh8x <test@example.com>

* Reduce internal-only labeling noise in source comments (Gitlawb#355)

This pass rewrites comment-only ANT-ONLY markers to neutral internal-only
language across the source tree without changing runtime strings, flags,
commands, or protocol identifiers. The goal is to lower obvious internal
prose leakage while keeping the diff mechanically safe and easy to review.

Constraint: Phase B is limited to comments/prose only; runtime strings and user-facing labels remain deferred
Rejected: Broad search-and-replace across strings and command descriptions | too risky for a prose-only pass
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Remaining ANT-ONLY hits are mostly runtime/user-facing strings and should be handled separately from comment cleanup
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Neutralize internal Anthropic prose in explanatory comments (Gitlawb#357)

This is a small prose-only follow-up that rewrites clearly internal or
explanatory Anthropic comment language to neutral wording in a handful of
high-confidence files. It avoids runtime strings, flags, command labels,
protocol identifiers, and provider-facing references.

Constraint: Keep this pass narrowly scoped to comments/documentation only
Rejected: Broader Anthropic comment sweep across functional API/protocol references | too ambiguous for a safe prose-only PR
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Leave functional Anthropic references (API behavior, SDKs, URLs, provider labels, protocol docs) for separate reviewed passes
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Neutralize remaining internal-only diagnostic labels (Gitlawb#359)

This pass rewrites a small set of ant-only diagnostic and UI labels to
neutral internal wording while leaving command definitions, flags, and
runtime logic untouched. It focuses on internal debug output, dead UI
branches, and noninteractive headings rather than broader product text.

Constraint: Label cleanup only; do not change command semantics or ant-only logic gates
Rejected: Renaming ant-only command descriptions in main.tsx | broader UX surface better handled in a separate reviewed pass
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Remaining ANT-ONLY hits are mostly command descriptions and intentionally deferred user-facing strings
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Finish eliminating remaining ANT-ONLY source labels (Gitlawb#360)

This extends the label-only cleanup to the remaining internal-only command,
debug, and heading strings so the source tree no longer contains ANT-ONLY
markers. The pass still avoids logic changes and only renames labels shown
in internal or gated surfaces.

Constraint: Update the existing label-cleanup PR without widening scope into behavior changes
Rejected: Leave the last ANT-ONLY strings for a later pass | low-cost cleanup while the branch is already focused on labels
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: The next phase should move off label cleanup and onto a separately scoped logic or rebrand slice
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Stub internal-only recording and model capability helpers (Gitlawb#377)

This follow-up Phase C-lite slice replaces purely internal helper modules
with stable external no-op surfaces and collapses internal elevated error
logging to a no-op. The change removes additional USER_TYPE-gated helper
behavior without touching product-facing runtime flows.

Constraint: Keep this PR limited to isolated helper modules that are already external no-ops in practice
Rejected: Pulling in broader speculation or logging sink changes | less isolated and easier to debate during review
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Continue Phase C with similarly isolated helpers before moving into mixed behavior files
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

Co-authored-by: anandh8x <test@example.com>

* Remove internal-only bundled skills and mock helpers (Gitlawb#376)

* Remove internal-only bundled skills and mock rate-limit behavior

This takes the next planned Phase C-lite slice by deleting bundled skills
that only ever registered for internal users and replacing the internal
mock rate-limit helper with a stable no-op external stub. The external
build keeps the same behavior while removing a concentrated block of
USER_TYPE-gated dead code.

Constraint: Limit this PR to isolated internal-only helpers and avoid bridge, oauth, or rebrand behavior
Rejected: Broad USER_TYPE cleanup across mixed runtime surfaces | too risky for the next medium-sized PR
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: The next cleanup pass should continue with similarly isolated USER_TYPE helpers before touching main.tsx or protocol-heavy code
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy)

* Align internal-only helper removal with remaining user guidance

This follow-up fixes the mock billing stub to be a true no-op and removes
stale user-facing references to /verify and /skillify from the same PR.
It also leaves a clearer paper trail for review: the deleted verify skill
was explicitly ant-gated before removal, and the remaining mock helper
callers still resolve to safe no-op returns in the external build.

Constraint: Keep the PR focused on consistency fixes and reviewer-requested evidence, not new cleanup scope
Rejected: Leave stale guidance for a later PR | would make this branch internally inconsistent after skill removal
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When deleting gated features, always sweep user guidance and coordinator prompts in the same pass
Tested: bun run build
Tested: bun run smoke
Tested: bun run verify:privacy
Tested: bun run test:provider
Tested: bun run test:provider-recommendation
Not-tested: Full repo typecheck (upstream baseline remains noisy; changed-file scan still shows only pre-existing tipRegistry errors outside edited lines)

* Clarify generic workflow wording after skill removal

This removes the last generic verification-skill wording that could still
be read as pointing at a deleted bundled command. The guidance now talks
about project workflows rather than a specific bundled verify skill.

Constraint: Keep the follow-up limited to reviewer-facing wording cleanup on the same PR
Rejected: Leave generic wording as-is | still too easy to misread after the explicit /verify references were removed
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When removing bundled commands, scrub both explicit and generic references in the same branch
Tested: bun run build
Tested: bun run smoke
Not-tested: Additional checks unchanged by wording-only follow-up

---------

Co-authored-by: anandh8x <test@example.com>

* test(api): add GEMINI_AUTH_MODE to environment setup in tests

* test: isolate GitHub/Gemini credential tests with fresh module imports and explicit non-bare env setup to prevent cross-test mock/cache leaks

* fix: update GitHub Copilot base URL and model defaults for improved compatibility

* fix: enhance error handling in OpenAI API response processing

* fix: improve error handling for GitHub Copilot API responses and streamline error body consumption

* fix: enhance response handling in OpenAI API shim for better error reporting and support for streaming responses

* feat: enhance GitHub device flow with fresh module import and token validation improvements

* fix: separate Copilot API routing from GitHub Models, clear stale env vars, honor providerOverride.apiKey

* fix: route GitHub GPT-5/Codex to Copilot API, show all Copilot models in picker, clear stale env vars

* fix GitHub Models API regression

* feat: update GitHub authentication to require OAuth tokens, normalize model handling for Copilot and GitHub Models

* fix: update GitHub token validation to support OAuth tokens and improve endpoint type handling

---------

Co-authored-by: Anandan <anandan.8x@gmail.com>
Co-authored-by: anandh8x <test@example.com>
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.