agent-ecosystem/test/features/codex-runtime-profile/resolveCodexRuntimeProfile.test.ts
2026-04-21 22:22:47 +03:00

237 lines
7.2 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
buildCodexFastModeArgs,
resolveCodexFastMode,
resolveCodexRuntimeSelection,
} from '../../../src/features/codex-runtime-profile/core/domain/resolveCodexRuntimeProfile';
import type { CliProviderModelCatalog, CliProviderStatus } from '../../../src/shared/types';
function makeCodexCatalog(overrides?: Partial<CliProviderModelCatalog>): CliProviderModelCatalog {
return {
schemaVersion: 1,
providerId: 'codex',
source: 'app-server',
status: 'ready',
fetchedAt: '2026-04-21T00:00:00.000Z',
staleAt: '2026-04-21T00:01:00.000Z',
defaultModelId: 'gpt-5.4',
defaultLaunchModel: 'gpt-5.4',
models: [
{
id: 'gpt-5.4',
launchModel: 'gpt-5.4',
displayName: 'GPT-5.4',
hidden: false,
supportedReasoningEfforts: ['low', 'medium', 'high', 'xhigh'],
defaultReasoningEffort: 'medium',
inputModalities: ['text'],
supportsPersonality: false,
isDefault: true,
upgrade: false,
source: 'app-server',
},
{
id: 'gpt-5.4-mini',
launchModel: 'gpt-5.4-mini',
displayName: 'GPT-5.4 Mini',
hidden: false,
supportedReasoningEfforts: ['low', 'medium', 'high'],
defaultReasoningEffort: 'medium',
inputModalities: ['text'],
supportsPersonality: false,
isDefault: false,
upgrade: false,
source: 'app-server',
},
{
id: 'gpt-5.5',
launchModel: 'gpt-5.5',
displayName: 'GPT-5.5',
hidden: false,
supportedReasoningEfforts: ['low', 'medium', 'high', 'xhigh'],
defaultReasoningEffort: 'medium',
inputModalities: ['text'],
supportsPersonality: false,
supportsFastMode: true,
isDefault: false,
upgrade: false,
source: 'app-server',
},
],
diagnostics: {
configReadState: 'ready',
appServerState: 'healthy',
},
...overrides,
};
}
function makeProviderStatus(overrides?: Partial<CliProviderStatus>): Partial<CliProviderStatus> {
return {
providerId: 'codex',
authenticated: true,
authMethod: 'chatgpt',
selectedBackendId: 'codex-native',
resolvedBackendId: 'codex-native',
backend: {
kind: 'codex-native',
label: 'Codex',
},
models: ['gpt-5.4', 'gpt-5.4-mini'],
modelCatalog: makeCodexCatalog(),
connection: {
supportsOAuth: true,
supportsApiKey: true,
configurableAuthModes: ['auto', 'chatgpt', 'api_key'],
configuredAuthMode: 'chatgpt',
apiKeyConfigured: false,
apiKeySource: null,
codex: {
preferredAuthMode: 'chatgpt',
effectiveAuthMode: 'chatgpt',
appServerState: 'healthy',
appServerStatusMessage: null,
managedAccount: {
type: 'chatgpt',
email: 'user@example.com',
planType: 'pro',
},
requiresOpenaiAuth: true,
login: {
status: 'idle',
error: null,
startedAt: null,
},
rateLimits: null,
launchAllowed: true,
launchIssueMessage: null,
launchReadinessState: 'ready_chatgpt',
},
},
...overrides,
};
}
describe('resolveCodexRuntimeProfile', () => {
it('allows explicit Fast for GPT-5.4 with ChatGPT auth on codex-native', () => {
const selection = resolveCodexRuntimeSelection({
source: { providerStatus: makeProviderStatus() },
selectedModel: 'gpt-5.4',
});
const fast = resolveCodexFastMode({ selection, selectedFastMode: 'on' });
expect(fast).toMatchObject({
selectedFastMode: 'on',
requestedFastMode: true,
resolvedFastMode: true,
selectable: true,
disabledReason: null,
capabilitySource: 'static-fallback',
creditCostMultiplier: 2,
speedMultiplier: 1.5,
});
});
it('allows explicit Fast for future catalog-declared Fast-capable models without changing static policy', () => {
const selection = resolveCodexRuntimeSelection({
source: { providerStatus: makeProviderStatus() },
selectedModel: 'gpt-5.5',
});
const fast = resolveCodexFastMode({ selection, selectedFastMode: 'on' });
expect(fast).toMatchObject({
selectedFastMode: 'on',
requestedFastMode: true,
resolvedFastMode: true,
selectable: true,
disabledReason: null,
capabilitySource: 'model-catalog',
});
});
it('keeps inherit safely off even when GPT-5.4 is eligible', () => {
const selection = resolveCodexRuntimeSelection({
source: { providerStatus: makeProviderStatus() },
selectedModel: 'gpt-5.4',
});
const fast = resolveCodexFastMode({ selection, selectedFastMode: 'inherit' });
expect(fast.selectable).toBe(true);
expect(fast.requestedFastMode).toBe(false);
expect(fast.resolvedFastMode).toBe(false);
});
it('disables Fast for API key mode with an API pricing reason', () => {
const providerStatus = makeProviderStatus({
authMethod: 'api_key',
connection: {
...makeProviderStatus().connection!,
codex: {
...makeProviderStatus().connection!.codex!,
effectiveAuthMode: 'api_key',
launchReadinessState: 'ready_api_key',
},
},
});
const selection = resolveCodexRuntimeSelection({
source: { providerStatus },
selectedModel: 'gpt-5.4',
});
const fast = resolveCodexFastMode({ selection, selectedFastMode: 'on' });
expect(fast.selectable).toBe(false);
expect(fast.resolvedFastMode).toBe(false);
expect(fast.disabledReason).toContain('API key mode uses standard API pricing');
});
it('disables Fast for models that do not expose Fast support', () => {
const selection = resolveCodexRuntimeSelection({
source: { providerStatus: makeProviderStatus() },
selectedModel: 'gpt-5.4-mini',
});
const fast = resolveCodexFastMode({ selection, selectedFastMode: 'on' });
expect(fast.selectable).toBe(false);
expect(fast.capabilitySource).toBe('unavailable');
expect(fast.disabledReason).toContain('not available for GPT-5.4 Mini');
});
it('disables Fast when catalog truth is degraded or missing', () => {
const degraded = resolveCodexRuntimeSelection({
source: {
providerStatus: makeProviderStatus({
modelCatalog: makeCodexCatalog({ status: 'degraded' }),
}),
},
selectedModel: 'gpt-5.4',
});
const missing = resolveCodexRuntimeSelection({
source: {
providerStatus: makeProviderStatus({
modelCatalog: null,
}),
},
selectedModel: 'gpt-5.4',
});
expect(resolveCodexFastMode({ selection: degraded, selectedFastMode: 'on' }).selectable).toBe(
false
);
expect(resolveCodexFastMode({ selection: missing, selectedFastMode: 'on' }).selectable).toBe(
false
);
});
it('builds official per-run Codex fast config overrides only for resolved Fast', () => {
expect(buildCodexFastModeArgs(true)).toEqual([
'-c',
'service_tier="fast"',
'-c',
'features.fast_mode=true',
]);
expect(buildCodexFastModeArgs(false)).toEqual([]);
expect(buildCodexFastModeArgs(null)).toEqual([]);
});
});