From cb8f8b7ac2e3e74516ee219a3a48156db7c6ed78 Mon Sep 17 00:00:00 2001 From: Juan Camilo Auriti Date: Fri, 10 Apr 2026 15:58:33 +0200 Subject: [PATCH] fix: let saved provider profiles win on restart (#513) Treat profile-managed env as restart state rather than explicit user intent so saved OpenAI-compatible profiles can replace stale Ollama values on startup and persist correctly across restarts. Co-authored-by: Claude Opus 4.6 --- src/utils/providerProfile.test.ts | 21 ++++++++++++++------- src/utils/providerProfile.ts | 23 ++++++++++++++++++++--- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/utils/providerProfile.test.ts b/src/utils/providerProfile.test.ts index 39dcc059..b5014931 100644 --- a/src/utils/providerProfile.test.ts +++ b/src/utils/providerProfile.test.ts @@ -485,24 +485,31 @@ test('buildStartupEnvFromProfile leaves explicit provider selections untouched', assert.equal(env.OPENAI_API_KEY, undefined) }) -test('buildStartupEnvFromProfile leaves profile-managed env untouched', async () => { +test('buildStartupEnvFromProfile lets saved startup profile override profile-managed env', async () => { const processEnv = { CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED: '1', - ANTHROPIC_BASE_URL: 'https://api.anthropic.com', - ANTHROPIC_MODEL: 'claude-sonnet-4-6', + CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED_ID: 'saved_ollama', + CLAUDE_CODE_USE_OPENAI: '1', + OPENAI_BASE_URL: 'http://localhost:11434/v1', + OPENAI_MODEL: 'llama3.1:8b', } const env = await buildStartupEnvFromProfile({ persisted: profile('openai', { OPENAI_API_KEY: 'sk-persisted', - OPENAI_MODEL: 'gpt-4o', + OPENAI_MODEL: 'Meta-Llama-3.1-70B-Instruct', + OPENAI_BASE_URL: 'https://api.sambanova.ai/v1', }), processEnv, }) - assert.equal(env, processEnv) - assert.equal(env.ANTHROPIC_MODEL, 'claude-sonnet-4-6') - assert.equal(env.OPENAI_MODEL, undefined) + assert.notEqual(env, processEnv) + assert.equal(env.CLAUDE_CODE_USE_OPENAI, '1') + assert.equal(env.OPENAI_API_KEY, 'sk-persisted') + assert.equal(env.OPENAI_MODEL, 'Meta-Llama-3.1-70B-Instruct') + assert.equal(env.OPENAI_BASE_URL, 'https://api.sambanova.ai/v1') + assert.equal(env.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED, undefined) + assert.equal(env.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED_ID, undefined) }) test('buildStartupEnvFromProfile treats explicit falsey provider flags as user intent', async () => { diff --git a/src/utils/providerProfile.ts b/src/utils/providerProfile.ts index f327779d..5f96d8d9 100644 --- a/src/utils/providerProfile.ts +++ b/src/utils/providerProfile.ts @@ -667,22 +667,39 @@ export async function buildStartupEnvFromProfile(options?: { readGeminiAccessToken?: () => string | undefined }): Promise { const processEnv = options?.processEnv ?? process.env - if (hasExplicitProviderSelection(processEnv)) { + const persisted = options?.persisted ?? loadProfileFile() + + // Saved /provider profiles should still win over provider-manager env that was + // auto-applied during startup. Only explicit shell/flag provider selection + // should bypass the persisted startup profile. + const profileManagedEnv = processEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED === '1' + if (hasExplicitProviderSelection(processEnv) && !profileManagedEnv) { return processEnv } - const persisted = options?.persisted ?? loadProfileFile() if (!persisted) { return processEnv } + const launchProcessEnv = profileManagedEnv + ? (() => { + const cleanedEnv = { ...processEnv } + for (const key of PROFILE_ENV_KEYS) { + delete cleanedEnv[key] + } + delete cleanedEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED + delete cleanedEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED_ID + return cleanedEnv + })() + : processEnv + return buildLaunchEnv({ profile: persisted.profile, persisted, goal: options?.goal ?? normalizeRecommendationGoal(processEnv.OPENCLAUDE_PROFILE_GOAL), - processEnv, + processEnv: launchProcessEnv, getOllamaChatBaseUrl: options?.getOllamaChatBaseUrl ?? getOllamaChatBaseUrl, resolveOllamaDefaultModel: options?.resolveOllamaDefaultModel,