diff --git a/src/main/services/schedule/ScheduledTaskExecutor.ts b/src/main/services/schedule/ScheduledTaskExecutor.ts index 01577b0d..43cabf0b 100644 --- a/src/main/services/schedule/ScheduledTaskExecutor.ts +++ b/src/main/services/schedule/ScheduledTaskExecutor.ts @@ -55,15 +55,6 @@ function buildProviderFastModeArgs(config: ScheduleLaunchConfig): string[] { } function validateFastModeLaunchConfig(config: ScheduleLaunchConfig): void { - if ( - config.providerId === 'codex' && - config.fastMode === 'on' && - config.resolvedFastMode !== true - ) { - throw new Error( - 'Codex Fast mode was requested for this schedule, but the saved launch profile is not Fast-eligible. Reopen the schedule and save it again with a supported ChatGPT account configuration.' - ); - } if (config.providerId !== 'codex' || config.resolvedFastMode !== true) { return; } diff --git a/src/main/services/team/TeamProvisioningService.ts b/src/main/services/team/TeamProvisioningService.ts index b142e1bf..0402addd 100644 --- a/src/main/services/team/TeamProvisioningService.ts +++ b/src/main/services/team/TeamProvisioningService.ts @@ -4987,22 +4987,8 @@ export class TeamProvisioningService { ); } - const codexSelection = resolveCodexSelectionFromFacts({ - selectedModel: params.model, - facts: params.facts, - }); - const codexFastResolution = resolveCodexFastMode({ - selection: codexSelection, - selectedFastMode: params.fastMode, - }); - if ((params.fastMode ?? 'inherit') === 'on' && !codexFastResolution.selectable) { - throw new Error( - `${params.actorLabel} enables Codex Fast mode, but ${ - codexFastResolution.disabledReason ?? - 'it is unavailable for the selected runtime, model, or auth mode.' - }` - ); - } + // Codex Fast is optional acceleration. If it is no longer eligible, the launch identity + // resolves it to normal Codex mode instead of blocking an otherwise launch-ready model. if (!explicitModel || params.facts.modelIds.has(explicitModel)) { return; diff --git a/test/main/services/schedule/ScheduledTaskExecutor.test.ts b/test/main/services/schedule/ScheduledTaskExecutor.test.ts index d2ebed47..15ccddeb 100644 --- a/test/main/services/schedule/ScheduledTaskExecutor.test.ts +++ b/test/main/services/schedule/ScheduledTaskExecutor.test.ts @@ -529,26 +529,32 @@ describe('ScheduledTaskExecutor', () => { proc.emit('close', 0); }); - it('rejects explicit Codex schedule Fast before spawn when saved eligibility is false', async () => { + it('runs a standard Codex schedule when saved Fast eligibility is false', async () => { + const proc = createMockProcess(); + mockSpawnCli.mockReturnValue(proc); + const executor = new ScheduledTaskExecutor(); - await expect( - executor.execute( - makeRequest({ - config: { - cwd: '/tmp/project', - prompt: 'do it', - providerId: 'codex', - providerBackendId: 'codex-native', - model: 'gpt-5.4-mini', - fastMode: 'on', - resolvedFastMode: false, - }, - }) - ) - ).rejects.toThrow('Codex Fast mode was requested'); + void executor.execute( + makeRequest({ + config: { + cwd: '/tmp/project', + prompt: 'do it', + providerId: 'codex', + providerBackendId: 'codex-native', + model: 'gpt-5.4-mini', + fastMode: 'on', + resolvedFastMode: false, + }, + }) + ); + await flushAsync(); - expect(mockSpawnCli).not.toHaveBeenCalled(); + const args = mockSpawnCli.mock.calls[0][1] as string[]; + expect(args).not.toContain('service_tier="fast"'); + expect(args).not.toContain('features.fast_mode=true'); + + proc.emit('close', 0); }); it('does not hard-code Codex Fast schedules to GPT-5.4 when saved eligibility is true', async () => { diff --git a/test/main/services/team/TeamProvisioningServicePrepare.test.ts b/test/main/services/team/TeamProvisioningServicePrepare.test.ts index 55ec9e58..453c2685 100644 --- a/test/main/services/team/TeamProvisioningServicePrepare.test.ts +++ b/test/main/services/team/TeamProvisioningServicePrepare.test.ts @@ -4556,7 +4556,7 @@ describe('TeamProvisioningService prepare/auth behavior', () => { }); }); - it('rejects explicit Codex Fast before launch when auth or model eligibility is invalid', () => { + it('allows explicit Codex Fast to downgrade before launch when auth or model eligibility is invalid', () => { const svc = new TeamProvisioningService(); const facts = { defaultModel: 'gpt-5.4-mini', @@ -4624,7 +4624,27 @@ describe('TeamProvisioningService prepare/auth behavior', () => { fastMode: 'on', facts, }) - ).toThrow('enables Codex Fast mode'); + ).not.toThrow(); + + expect( + (svc as any).buildProviderModelLaunchIdentity({ + request: { + providerId: 'codex', + providerBackendId: 'codex-native', + model: 'gpt-5.4-mini', + fastMode: 'on', + }, + facts, + }) + ).toMatchObject({ + providerId: 'codex', + providerBackendId: 'codex-native', + selectedModel: 'gpt-5.4-mini', + resolvedLaunchModel: 'gpt-5.4-mini', + selectedFastMode: 'on', + resolvedFastMode: false, + fastResolutionReason: expect.stringContaining('API key mode uses standard API pricing'), + }); }); it('rejects Anthropic max and fast when the exact resolved launch model does not support them', () => {