Skip to content

fix: preserve explicit startup provider selection#468

Open
gnanam1990 wants to merge 4 commits intomainfrom
fix/provider-precedence-startup-freeze
Open

fix: preserve explicit startup provider selection#468
gnanam1990 wants to merge 4 commits intomainfrom
fix/provider-precedence-startup-freeze

Conversation

@gnanam1990
Copy link
Copy Markdown
Collaborator

Summary

  • Fix Still freezing #464 by making explicit --provider startup selection take precedence over persisted GitHub onboarding state.
  • Prevent startup settings hydration from reapplying GitHub Models mode when the user explicitly launches with another provider such as --provider openai.
  • Defer REPL startup checks until the initial prompt input window is idle, reducing the risk of launch-time input freezes caused by startup plugin work.
  • Add focused regression tests for provider-flag precedence, settings-env filtering, and REPL startup-check gating.

Root Cause

This issue turned out to be a combination of two older bug paths:

  1. GitHub onboarding persisted:
  • CLAUDE_CODE_USE_GITHUB=1
  • OPENAI_MODEL=github:copilot
  1. On later launches, --provider was applied early, but settings hydration could still reapply GitHub provider state afterward.

  2. REPL startup checks were still running immediately on mount, which matches the known startup freeze family from earlier reports.

In practice, this could leave users stuck reopening in GitHub Models mode and then hitting a launch-time freeze path.

What Changed

  • Normalize explicit CLI provider selection so conflicting provider flags are cleared when --provider is used.
  • Preserve explicit startup provider intent through settings hydration instead of letting persisted GitHub onboarding env override it.
  • Strip stale github:copilot model state when the explicit provider is not GitHub.
  • Defer performStartupChecks() until after the initial prompt suppression window so startup work does not land in the first input window.
  • Add regression coverage for both the provider-selection path and the REPL startup-check timing path.

Test Plan

  • npx bun test src/utils/providerFlag.test.ts src/utils/providerEnvSelection.test.ts src/screens/replStartupGates.test.ts
  • npx bun test
  • npx bun run smoke
  • PTY startup check with temp user settings forcing persisted GitHub mode, then launching node dist/cli.mjs --provider openai
  • Verified startup banner showed:
    • Provider OpenAI
    • Model gpt-4o
    • Endpoint https://api.openai.com/v1

Notes

  • I was able to verify the startup/provider side locally.
  • The freeze itself appears environment-dependent, so confirmation from the original reporter on the PR branch/build will be the best validation of the remaining user-facing symptom.

@gnanam1990 gnanam1990 mentioned this pull request Apr 7, 2026
@gnanam1990 gnanam1990 force-pushed the fix/provider-precedence-startup-freeze branch from a0a0606 to 65dd19c Compare April 7, 2026 04:40
@gnanam1990
Copy link
Copy Markdown
Collaborator Author

Reporter validation update: the affected user tested the PR and confirmed it is now working fine.\n\nIssue comment: #464 (comment)

kevincodex1
kevincodex1 previously approved these changes Apr 7, 2026
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
Copy link
Copy Markdown
Contributor

one more eyes when you can bro @Vasanthdev2004

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 current head 65dd19cf87718e6ee1beb03c833bebad2daf96eb against current origin/main.

The branch does fix the original GitHub-onboarding precedence issue for the specific --provider openai path it targets, and the focused tests/build/smoke are green. I still can't approve because there are two provider-selection regressions in the generalized fix.

  1. src/utils/managedEnv.ts:87-95, src/utils/managedEnv.ts:146-166, src/utils/providerEnvSelection.ts:22-31, src/utils/providerEnvSelection.ts:40-54
    filterSettingsEnvForExplicitProvider() is documented/tested as an explicit-CLI-provider filter, but it also treats any already-present CLAUDE_CODE_USE_* flag in process.env as "explicit".

    Because applySafeConfigEnvironmentVariables() applies settings sources sequentially, that inverts source precedence:

    • an earlier settings source can set CLAUDE_CODE_USE_GITHUB=1
    • a later settings source trying to switch to OpenAI/another provider gets stripped instead of winning

    Direct helper-level repro I verified locally on this head:

    • processEnv = { CLAUDE_CODE_USE_GITHUB: '1' }
    • env = { CLAUDE_CODE_USE_OPENAI: '1', OPENAI_MODEL: 'gpt-4o', OTHER: 'keep-me' }
    • filterSettingsEnvForExplicitProvider(env, processEnv) returns only { OTHER: 'keep-me' }

    So this no longer means "explicit CLI provider wins"; it means "whichever provider flag got applied first wins", which is a real precedence regression.

  2. src/utils/providerFlag.ts:85-86, src/utils/providerProfile.ts:407-422, src/utils/providerProfile.ts:669-672
    --provider anthropic is still not treated as an explicit startup selection by the saved-profile startup path.

    The branch records CLAUDE_CODE_EXPLICIT_PROVIDER=anthropic, but buildStartupEnvFromProfile() still decides explicit-provider intent only from CLAUDE_CODE_USE_* flags / CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED. Since anthropic clears all CLAUDE_CODE_USE_* flags, a persisted GitHub/OpenAI profile can still override the user's explicit CLI choice.

    Direct repro I verified locally on this head:

    • call applyProviderFlag('anthropic', [])
    • call buildStartupEnvFromProfile() with a persisted GitHub profile
    • result is not the original process.env; it comes back with CLAUDE_CODE_USE_OPENAI='1' and OPENAI_MODEL='github:copilot'

    So an explicit --provider anthropic startup can still be pulled back into the persisted profile path.

Non-blocking note:

  • src/screens/REPL.tsx now delays startup checks until the prompt is empty, not merely idle, which may be stricter than intended, but I am not blocking on that without a clearer product regression repro.

What I verified on this head:

  • bun test src/utils/providerFlag.test.ts src/utils/providerEnvSelection.test.ts src/screens/replStartupGates.test.ts -> 31 pass
  • bun run build -> success
  • bun run smoke -> success
  • direct repro of the settings-source precedence regression above
  • direct repro that explicit --provider anthropic is overridden by a persisted GitHub profile

I would not merge this until the filtering is limited to truly explicit startup provider intent, and --provider anthropic is treated as explicit by the saved-profile startup path too.

@gnanam1990
Copy link
Copy Markdown
Collaborator Author

Thanks for the detailed recheck. I pushed a narrow follow-up that addresses both provider-selection regressions you called out.

What changed:

  • filterSettingsEnvForExplicitProvider() now treats only CLAUDE_CODE_EXPLICIT_PROVIDER as a true explicit startup override. Plain CLAUDE_CODE_USE_* flags in process.env no longer trigger the filter, so trusted settings sources keep their normal precedence.
  • hasExplicitProviderSelection() now honors CLAUDE_CODE_EXPLICIT_PROVIDER directly, which preserves explicit --provider anthropic startup intent through the saved-profile startup path.

Added regression coverage for both cases:

  • plain provider flags do not count as explicit CLI overrides
  • explicit anthropic startup is not overridden by a persisted GitHub/OpenAI profile

Local verification:

  • npx bun test src/utils/providerFlag.test.ts src/utils/providerEnvSelection.test.ts src/utils/providerProfile.test.ts
  • npx bun test
  • npx bun run build
  • npx bun run smoke

I also rechecked the two direct repro paths locally:

  1. persisted GitHub onboarding + --provider openai still stays on OpenAI
  2. explicit --provider anthropic is no longer overridden by a persisted GitHub/OpenAI profile

kevincodex1
kevincodex1 previously approved these changes Apr 7, 2026
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 current head 139610950c6f9bf4bab32e7779fa7c4d5d331253 against current origin/main.

The latest push fixes the two blockers I raised on the previous head:

  • settings-source precedence is no longer inverted by plain CLAUDE_CODE_USE_* flags
  • buildStartupEnvFromProfile() now preserves explicit --provider anthropic

I still can't approve because there is one remaining explicit-provider regression on the current startup path.

  1. src/utils/providerFlag.ts:85-86, src/utils/managedEnv.ts:183-185, src/utils/providerProfiles.ts:255-265,417-433
    --provider anthropic is still overridden by an active saved provider profile during startup.

    The new CLAUDE_CODE_EXPLICIT_PROVIDER marker is respected by:

    • filterSettingsEnvForExplicitProvider()
    • buildStartupEnvFromProfile()

    But applySafeConfigEnvironmentVariables() still calls applyActiveProviderProfileFromConfig(), and that path only guards on hasProviderSelectionFlags(processEnv), which still ignores CLAUDE_CODE_EXPLICIT_PROVIDER.

    Direct repro I verified locally on this head:

    • call applyProviderFlag('anthropic', [])
    • call applyActiveProviderProfileFromConfig() with an active GitHub profile config
    • result:
      • returned profile id is gh
      • CLAUDE_CODE_USE_OPENAI='1'
      • OPENAI_MODEL='github:copilot'

    So explicit startup intent is still not preserved end-to-end: it survives the saved-profile bootstrap path, but it is still clobbered by the later active-profile application path.

Non-blocking note:

  • src/screens/REPL.tsx:1336-1352 now waits for promptTypingSuppressionActive === false, and that helper stays true for any non-empty draft, not just active typing. I did not block on this without a clearer user-facing regression repro, but the behavior is stricter than "wait until startup is idle" suggests.

What I verified on this head:

  • bun test src/utils/providerFlag.test.ts src/utils/providerEnvSelection.test.ts src/utils/providerProfile.test.ts src/screens/replStartupGates.test.ts -> 71 pass
  • bun run build -> success
  • bun run smoke -> success
  • direct repro that filterSettingsEnvForExplicitProvider() now preserves later settings-source precedence
  • direct repro that buildStartupEnvFromProfile() preserves explicit anthropic startup intent
  • direct repro that applyActiveProviderProfileFromConfig() still overrides explicit --provider anthropic

I would not merge this until the active-profile application path also treats CLAUDE_CODE_EXPLICIT_PROVIDER as explicit startup intent.

@gnanam1990
Copy link
Copy Markdown
Collaborator Author

@Vasanthdev2004 I pushed one more narrow follow-up for the remaining active-profile path on the latest head:

  • b2cabdd fix: preserve explicit provider intent for active profiles

This updates applyActiveProviderProfileFromConfig() so active saved profiles also respect CLAUDE_CODE_EXPLICIT_PROVIDER, which closes the last --provider anthropic override path you called out.

Local recheck on this head:

  • npx bun test src/utils/providerFlag.test.ts src/utils/providerEnvSelection.test.ts src/utils/providerProfile.test.ts src/utils/providerProfiles.test.ts
  • npx bun test
  • npx bun run build
  • npx bun run smoke
  • direct repro now returns applied: null for explicit anthropic + active saved GitHub profile

When you have a moment, could you please re-review the latest commit?

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 current head b2cabdd950eeee5ed0f9c50d42f63e963e04201e against current origin/main.

The latest push fixes the previous blocker I raised:

  • active provider profiles now respect CLAUDE_CODE_EXPLICIT_PROVIDER, so explicit --provider anthropic startup intent is preserved end-to-end

I still can't approve because there is one remaining explicit-provider regression in the generalized fix.

  1. src/utils/providerFlag.ts:118-123, src/utils/providerEnvSelection.ts:39-55, src/utils/managedEnv.ts:87-95,140-166
    --provider ollama is still overridable by settings-sourced OpenAI routing env, so the new ?explicit provider? path does not actually preserve Ollama startup intent.

    applyProviderFlag('ollama', ...) encodes Ollama as:

    • CLAUDE_CODE_USE_OPENAI=1
    • OPENAI_BASE_URL=http://localhost:11434/v1
    • OPENAI_API_KEY=ollama

    But filterSettingsEnvForExplicitProvider() only strips provider flags plus a GitHub-model special case. It does not strip OpenAI routing env for explicit non-GitHub OpenAI-compatible providers like Ollama.

    Direct repro I verified locally on this head:

    • call applyProviderFlag('ollama', [])
    • then filter settings env containing:
      • OPENAI_BASE_URL='https://api.openai.com/v1'
      • OPENAI_MODEL='gpt-4o'
      • OPENAI_API_KEY='sk-test'
    • filterSettingsEnvForExplicitProvider(...) returns those values unchanged

    Since applySafeConfigEnvironmentVariables() merges filtered settings env afterward, a user launching with --provider ollama can still be rerouted back to a remote OpenAI endpoint from trusted settings. That means the branch still does not preserve explicit startup provider intent for all supported providers; it currently special-cases GitHub/Anthropic but leaves Ollama exposed.

Non-blocking note:

  • I could not reproduce a user-facing startup-check regression, but the REPL change still waits for promptTypingSuppressionActive === false, which is stricter than just ?wait until startup is idle?. I am not blocking on that without a clearer symptom repro.

What I verified on this head:

  • bun test src/utils/providerFlag.test.ts src/utils/providerEnvSelection.test.ts src/utils/providerProfile.test.ts src/utils/providerProfiles.test.ts src/screens/replStartupGates.test.ts -> 71 pass
  • direct repro that applyActiveProviderProfileFromConfig() no longer overrides explicit --provider anthropic
  • direct repro that explicit --provider ollama still allows OPENAI_BASE_URL / OPENAI_MODEL / OPENAI_API_KEY from settings through the filter
  • current GitHub Actions checks on this head are green

I would not merge this until explicit-provider filtering also protects Ollama/OpenAI-compatible startup intent, not just GitHub-model and anthropic paths.

@gnanam1990
Copy link
Copy Markdown
Collaborator Author

Thanks again for the careful rechecks. I pushed one more narrow follow-up for the remaining Ollama path on the latest head:

  • b5dbb71 fix: preserve explicit ollama startup intent

This closes the last explicit-provider override you called out:

  • explicit --provider ollama now strips settings-sourced OPENAI_BASE_URL, OPENAI_MODEL, and OPENAI_API_KEY, so trusted settings can no longer reroute an Ollama startup back to remote OpenAI.

Local recheck on this head:

  • npx bun test src/utils/providerEnvSelection.test.ts
  • npx bun test src/utils/providerFlag.test.ts src/utils/providerEnvSelection.test.ts src/utils/providerProfile.test.ts src/utils/providerProfiles.test.ts
  • npx bun test
  • npx bun run build
  • npx bun run smoke

I also rechecked the direct repros locally:

  1. explicit ollama no longer allows remote OpenAI routing env through the filter
  2. explicit anthropic is still not overridden by an active saved profile
  3. persisted GitHub onboarding + --provider openai still stays on OpenAI

One small request for future rounds: if possible, it would really help to include all identified blockers in a single review pass when they’re visible together. That makes it easier to address the full provider-precedence surface in one try and reduces the back-and-forth on adjacent startup paths.

When you have a moment, could you please re-review the latest commit?

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.

No blocking findings on the current head b5dbb71a4431b249d1e64e2a42c5d50c17e31eac relative to current origin/main.

What I verified:

  • bun test src/utils/providerFlag.test.ts src/utils/providerEnvSelection.test.ts src/utils/providerProfile.test.ts src/utils/providerProfiles.test.ts src/screens/replStartupGates.test.ts
  • direct repro that explicit --provider ollama now strips settings-sourced OPENAI_BASE_URL / OPENAI_MODEL / OPENAI_API_KEY
  • direct repro that applyActiveProviderProfileFromConfig() no longer overrides explicit --provider anthropic
  • bun run build
  • bun run smoke
  • current GitHub Actions checks on this head are all green

Non-blocking note:

  • src/screens/REPL.tsx still waits for promptTypingSuppressionActive === false, which means background startup checks are delayed while any non-empty draft remains in the prompt. I did not find a clear product regression from that on this branch, but it is a behavior change worth keeping an eye on.

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.

Still freezing

3 participants