From 3c7caf25c6de793675434f548963d5e37d3be601 Mon Sep 17 00:00:00 2001 From: jatmn Date: Wed, 4 Nov 2026 20:15:54 -0800 Subject: [PATCH] fix(requesty): restore a keyed Requesty profile's key on reconcile A keyed canonical Requesty profile installs its saved key as REQUESTY_API_KEY, and the request executor prefers that variable on the Requesty route. Settings env is merged into the process after the profile applies. applyActiveProviderProfileFromConfig then reapplies the profile only when isProcessEnvAlignedWithProfile reports drift, and that check compared ApiSmart, API Route and Command Code dedicated keys but not REQUESTY_API_KEY. A settings or shell REQUESTY_API_KEY therefore survived reconcile and was sent instead of the selected profile's saved key. The alignment check now compares REQUESTY_API_KEY for a keyed canonical Requesty profile, so reconcile restores the saved key. A keyless profile still uses shell or settings input. Co-Authored-By: Claude Opus 5.5 --- src/utils/providerProfiles.test.ts | 16 ++++++++++++++++ src/utils/providerProfiles.ts | 6 ++++++ 2 files changed, 22 insertions(+) diff --git a/src/utils/providerProfiles.test.ts b/src/utils/providerProfiles.test.ts index 1e6d2cc1d..fa16e0e3c 100644 --- a/src/utils/providerProfiles.test.ts +++ b/src/utils/providerProfiles.test.ts @@ -6880,6 +6880,22 @@ test.each([false, true])('a keyless Runcrate selection rejects another profile k expect(persisted.env.RUNCRATE_API_KEY).toBeUndefined() }) +// Settings env can overwrite REQUESTY_API_KEY after the profile applied. The +// request executor prefers that variable on the Requesty route, so reconcile +// must restore the selected profile's saved key. +test('a keyed Requesty profile restores its saved key over a drifted settings key', async () => { + const { setActiveProviderProfile, applyActiveProviderProfileFromConfig } = + await importFreshProviderProfileModules() + const saved = buildRequestyProfile({ apiKey: 'selected-requesty-key' }) + saveMockGlobalConfig(current => ({ ...current, providerProfiles: [saved] })) + setActiveProviderProfile(saved.id, { configDir: testConfigDir! }) + process.env.REQUESTY_API_KEY = 'settings-requesty-key' + expect(applyActiveProviderProfileFromConfig()?.id).toBe(saved.id) + expect(process.env.REQUESTY_API_KEY).toBe('selected-requesty-key') + expect(resolveRouteCredentialValue({ routeId: 'requesty', baseUrl: saved.baseUrl })) + .toBe('selected-requesty-key') +}) + // A keyed Requesty profile mirrors its saved key into REQUESTY_API_KEY. A // keyless Requesty selection that follows must not adopt that key as shell // input, in process or after a relaunch from the keyed startup file. diff --git a/src/utils/providerProfiles.ts b/src/utils/providerProfiles.ts index 4be33cdff..85ed98a85 100644 --- a/src/utils/providerProfiles.ts +++ b/src/utils/providerProfiles.ts @@ -1178,6 +1178,12 @@ function isProcessEnvAlignedWithProfile( ? !includeApiKey || sameOptionalEnvValue(processEnv.API_ROUTE_API_KEY, profile.apiKey) : true) && + // A keyless Requesty profile uses shell or settings input; a keyed one + // owns REQUESTY_API_KEY, which requests prefer over OPENAI_API_KEY. + (isRequestyProfile(profile) && profile.apiKey + ? !includeApiKey || + sameOptionalEnvValue(processEnv.REQUESTY_API_KEY, profile.apiKey) + : true) && (isCommandcodeProfile(profile) ? !includeApiKey || sameOptionalEnvValue(