From 591f4a08af9d1a637cc6fde9fbfc74817780ffd9 Mon Sep 17 00:00:00 2001 From: jatmn Date: Wed, 4 Nov 2026 18:56:21 -0800 Subject: [PATCH] fix(requesty): scope the copied Requesty key to the Requesty route ccab79e2 let an OPENAI_API_KEY equal to REQUESTY_API_KEY take precedence as a copied provider key on every route, so a stale mirror could be sent to another provider such as xAI instead of its own key. Count it as copied only when the active route is requesty. The pool test now sets the mirrored state directly instead of running the override helper against the shared process env. Co-Authored-By: Claude Opus 5.5 --- .../api/openaiShim/requestExecutor.test.ts | 29 ++++++++++++++----- .../api/openaiShim/requestExecutor.ts | 6 +++- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/services/api/openaiShim/requestExecutor.test.ts b/src/services/api/openaiShim/requestExecutor.test.ts index a086c7070..20fc95d1f 100644 --- a/src/services/api/openaiShim/requestExecutor.test.ts +++ b/src/services/api/openaiShim/requestExecutor.test.ts @@ -7,7 +7,6 @@ import { acquireSharedMutationLock, releaseSharedMutationLock } from '../../../t import { asMockFetch } from '../../../test/typedMocks.js' import { _clearRegistryForTesting, ensureIntegrationsLoaded } from '../../../integrations/index.ts' import { applyProviderFlag } from '../../../utils/providerFlag.ts' -import { applyAgentProviderOverrideToEnv } from '../agentRouting.ts' import { categorizeRetryableAPIError, getAssistantMessageFromError, @@ -25,6 +24,7 @@ const originalEnv = { OPENAI_API_KEYS: process.env.OPENAI_API_KEYS, LLMTR_API_KEY: process.env.LLMTR_API_KEY, REQUESTY_API_KEY: process.env.REQUESTY_API_KEY, + XAI_API_KEY: process.env.XAI_API_KEY, API_ROUTE_API_KEY: process.env.API_ROUTE_API_KEY, CMD_API_KEY: process.env.CMD_API_KEY, COMMANDCODE_API_KEY: process.env.COMMANDCODE_API_KEY, @@ -188,6 +188,7 @@ beforeEach(async () => { delete process.env.OPENAI_API_KEYS delete process.env.LLMTR_API_KEY delete process.env.REQUESTY_API_KEY + delete process.env.XAI_API_KEY delete process.env.API_ROUTE_API_KEY delete process.env.CMD_API_KEY delete process.env.COMMANDCODE_API_KEY @@ -243,6 +244,7 @@ afterEach(() => { restoreEnv('OPENAI_API_KEYS', originalEnv.OPENAI_API_KEYS) restoreEnv('LLMTR_API_KEY', originalEnv.LLMTR_API_KEY) restoreEnv('REQUESTY_API_KEY', originalEnv.REQUESTY_API_KEY) + restoreEnv('XAI_API_KEY', originalEnv.XAI_API_KEY) restoreEnv('API_ROUTE_API_KEY', originalEnv.API_ROUTE_API_KEY) restoreEnv('CMD_API_KEY', originalEnv.CMD_API_KEY) restoreEnv('COMMANDCODE_API_KEY', originalEnv.COMMANDCODE_API_KEY) @@ -378,13 +380,12 @@ test('selected LLMTR route prefers its dedicated key over a generic OPENAI_API_K test('a Requesty key mirrored into OPENAI_API_KEY wins over an inherited OPENAI_API_KEYS pool', async () => { // A saved Requesty profile and a Requesty teammate override both mirror // their key into OPENAI_API_KEY; a parent's generic pool must not replace it. + process.env.CLAUDE_CODE_USE_OPENAI = '1' + process.env.OPENAI_BASE_URL = 'https://router.requesty.ai/v1' + process.env.OPENAI_MODEL = 'openai/gpt-5-mini' process.env.OPENAI_API_KEYS = 'parent-pool-key-a,parent-pool-key-b' - process.env.REQUESTY_API_KEY = 'parent-requesty-key' - applyAgentProviderOverrideToEnv({ - model: 'openai/gpt-5-mini', - baseURL: 'https://router.requesty.ai/v1', - apiKey: 'configured-agent-key', - }) + process.env.OPENAI_API_KEY = 'configured-agent-key' + process.env.REQUESTY_API_KEY = 'configured-agent-key' const captured = await captureChatCompletionRequest('openai/gpt-5-mini') @@ -392,6 +393,20 @@ test('a Requesty key mirrored into OPENAI_API_KEY wins over an inherited OPENAI_ expect(captured.authorization).toBe('Bearer configured-agent-key') }) +test('a Requesty key mirrored into OPENAI_API_KEY is not reused on another route', async () => { + process.env.CLAUDE_CODE_USE_OPENAI = '1' + process.env.OPENAI_BASE_URL = 'https://api.x.ai/v1' + process.env.OPENAI_MODEL = 'grok-4' + process.env.XAI_API_KEY = 'xai-key' + process.env.OPENAI_API_KEY = 'requesty-key' + process.env.REQUESTY_API_KEY = 'requesty-key' + + const captured = await captureChatCompletionRequest('grok-4') + + expect(captured.url).toBe('https://api.x.ai/v1/chat/completions') + expect(captured.authorization).toBe('Bearer xai-key') +}) + test('selected Command Code route sends CMD_API_KEY through the generic route credential resolver', async () => { process.env.CMD_API_KEY = 'cmd-key' delete process.env.COMMANDCODE_API_KEY diff --git a/src/services/api/openaiShim/requestExecutor.ts b/src/services/api/openaiShim/requestExecutor.ts index da3be6c8d..529cb56b2 100644 --- a/src/services/api/openaiShim/requestExecutor.ts +++ b/src/services/api/openaiShim/requestExecutor.ts @@ -333,7 +333,11 @@ export async function executeOpenAIRequest( requestProcessEnv.FIREWORKS_API_KEY, requestProcessEnv.LONGCAT_API_KEY, requestProcessEnv.LLMTR_API_KEY, - requestProcessEnv.REQUESTY_API_KEY, + // Requesty's key counts as copied only on its own route, so a stale + // mirror is never reused as another provider's credential. + runtimeShimContext.routeId === 'requesty' + ? requestProcessEnv.REQUESTY_API_KEY + : undefined, requestProcessEnv.CMD_API_KEY, requestProcessEnv.COMMANDCODE_API_KEY, requestProcessEnv.COMMAND_CODE_API_KEY,