fix(team): downgrade unavailable codex fast launches
This commit is contained in:
parent
0a3876e141
commit
08b1de7fa2
4 changed files with 47 additions and 44 deletions
|
|
@ -55,15 +55,6 @@ function buildProviderFastModeArgs(config: ScheduleLaunchConfig): string[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateFastModeLaunchConfig(config: ScheduleLaunchConfig): void {
|
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) {
|
if (config.providerId !== 'codex' || config.resolvedFastMode !== true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4987,22 +4987,8 @@ export class TeamProvisioningService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const codexSelection = resolveCodexSelectionFromFacts({
|
// Codex Fast is optional acceleration. If it is no longer eligible, the launch identity
|
||||||
selectedModel: params.model,
|
// resolves it to normal Codex mode instead of blocking an otherwise launch-ready 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.'
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!explicitModel || params.facts.modelIds.has(explicitModel)) {
|
if (!explicitModel || params.facts.modelIds.has(explicitModel)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -529,26 +529,32 @@ describe('ScheduledTaskExecutor', () => {
|
||||||
proc.emit('close', 0);
|
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();
|
const executor = new ScheduledTaskExecutor();
|
||||||
|
|
||||||
await expect(
|
void executor.execute(
|
||||||
executor.execute(
|
makeRequest({
|
||||||
makeRequest({
|
config: {
|
||||||
config: {
|
cwd: '/tmp/project',
|
||||||
cwd: '/tmp/project',
|
prompt: 'do it',
|
||||||
prompt: 'do it',
|
providerId: 'codex',
|
||||||
providerId: 'codex',
|
providerBackendId: 'codex-native',
|
||||||
providerBackendId: 'codex-native',
|
model: 'gpt-5.4-mini',
|
||||||
model: 'gpt-5.4-mini',
|
fastMode: 'on',
|
||||||
fastMode: 'on',
|
resolvedFastMode: false,
|
||||||
resolvedFastMode: false,
|
},
|
||||||
},
|
})
|
||||||
})
|
);
|
||||||
)
|
await flushAsync();
|
||||||
).rejects.toThrow('Codex Fast mode was requested');
|
|
||||||
|
|
||||||
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 () => {
|
it('does not hard-code Codex Fast schedules to GPT-5.4 when saved eligibility is true', async () => {
|
||||||
|
|
|
||||||
|
|
@ -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 svc = new TeamProvisioningService();
|
||||||
const facts = {
|
const facts = {
|
||||||
defaultModel: 'gpt-5.4-mini',
|
defaultModel: 'gpt-5.4-mini',
|
||||||
|
|
@ -4624,7 +4624,27 @@ describe('TeamProvisioningService prepare/auth behavior', () => {
|
||||||
fastMode: 'on',
|
fastMode: 'on',
|
||||||
facts,
|
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', () => {
|
it('rejects Anthropic max and fast when the exact resolved launch model does not support them', () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue