Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions desktop/recovered/refresh-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,17 @@
"modelSettings": {
"patched": false,
"results": []
},
"fastMode": {
"patched": true,
"results": [
{
"label": "fast mode missing service tiers guard",
"patched": true,
"skipped": false,
"reason": null
}
]
}
},
"nativeModuleSummary": {
Expand Down
54 changes: 54 additions & 0 deletions desktop/scripts/assemble-codex-runtime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,10 @@ const rendererDesktopGoalsFeaturePatchAlternatives = [
'computerUse:c.available,computerUseNodeRepl:c.available&&l,control:u,goals:!0,multiWindow:d})',
},
];
export const fastModeModelServiceTiersPatchTarget =
'return e.serviceTiers.length>0||e.additionalSpeedTiers?.includes(u)===!0';
export const fastModeModelServiceTiersPatchReplacement =
'return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0';
const composerGoalsSlashCommandPatchMarker = 'id:`goals`,title:`Goals`';
const composerGoalsSlashCommandPatchAlternatives = [
{
Expand Down Expand Up @@ -2052,6 +2056,55 @@ function patchCodexModelSettingsBundle(extractedAppRoot) {
);
}

export function patchFastModeServiceTiersGuard(filePath) {
assertExists(filePath, 'Patched extracted asset');

const source = fs.readFileSync(filePath, 'utf8');
if (source.includes(fastModeModelServiceTiersPatchTarget)) {
fs.writeFileSync(
filePath,
source
.split(fastModeModelServiceTiersPatchTarget)
.join(fastModeModelServiceTiersPatchReplacement),
'utf8',
);
return [
{
label: 'fast mode missing service tiers guard',
patched: true,
skipped: false,
reason: null,
},
];
}

if (source.includes(fastModeModelServiceTiersPatchReplacement)) {
return [
{
label: 'fast mode missing service tiers guard',
patched: false,
skipped: true,
reason: 'fast mode missing service tiers guard replacement already present',
},
];
}

throw buildMissingPatchTargetError('fast mode missing service tiers guard', filePath);
}

function patchCodexFastModeBundle(extractedAppRoot) {
const fastModePath = findOptionalExtractedWebviewAsset(
extractedAppRoot,
'use-is-fast-mode-enabled-',
);

if (fastModePath == null) {
return summarizePatchResults([]);
}

return summarizePatchResults(patchFastModeServiceTiersGuard(fastModePath));
}

function patchCodexAppServerHooks(extractedAppRoot) {
const appServerHooksPath = findExtractedWebviewAsset(extractedAppRoot, 'app-server-manager-hooks-');
return summarizePatchResults(
Expand Down Expand Up @@ -2121,6 +2174,7 @@ export function patchExtractedCodexApp(extractedAppRoot) {
avatarOverlayRenderer: patchCodexAvatarOverlayRenderer(extractedAppRoot),
authWebview: patchCodexAuthWebviewBundles(extractedAppRoot),
modelSettings: patchCodexModelSettingsBundle(extractedAppRoot),
fastMode: patchCodexFastModeBundle(extractedAppRoot),
};
}

Expand Down
185 changes: 185 additions & 0 deletions desktop/tests/linux/codex-runtime-assembly.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,191 @@ describe('codex runtime assembly guards', () => {
]);
});

test('allows the fast mode service-tier guard to be applied idempotently', () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-patch-'));
const filePath = path.join(tempRoot, 'use-is-fast-mode-enabled.js');

fs.writeFileSync(
filePath,
'function m(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}\n',
'utf8',
);

const result = runAssemblySnippet(
`
const patchResult = runtime.patchFastModeServiceTiersGuard(${JSON.stringify(filePath)});
process.stdout.write(JSON.stringify(patchResult));
`,
tempRoot,
);

expect(result.status).toBe(0);
expect(JSON.parse(result.stdout)).toEqual([
{
label: 'fast mode missing service tiers guard',
patched: false,
skipped: true,
reason: 'fast mode missing service tiers guard replacement already present',
},
]);
});

test('replaces the unsafe fast mode service-tier access', () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-patch-'));
const filePath = path.join(tempRoot, 'use-is-fast-mode-enabled.js');

fs.writeFileSync(
filePath,
'function m(e){return e.serviceTiers.length>0||e.additionalSpeedTiers?.includes(u)===!0}\n',
'utf8',
);

const result = runAssemblySnippet(
`
import fs from 'node:fs';
const patchResult = runtime.patchFastModeServiceTiersGuard(${JSON.stringify(filePath)});
process.stdout.write(JSON.stringify({
patchResult,
source: fs.readFileSync(${JSON.stringify(filePath)}, 'utf8'),
}));
`,
tempRoot,
);

expect(result.status).toBe(0);
expect(JSON.parse(result.stdout)).toEqual({
patchResult: [
{
label: 'fast mode missing service tiers guard',
patched: true,
skipped: false,
reason: null,
},
],
source:
'function m(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}\n',
});
});

test('fails loudly when the fast mode service-tier patch shape no longer matches', () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-patch-'));
const filePath = path.join(tempRoot, 'use-is-fast-mode-enabled.js');

fs.writeFileSync(
filePath,
'function m(e){return e.additionalSpeedTiers?.includes(u)===!0}\n',
'utf8',
);

const result = runAssemblySnippet(
`
try {
runtime.patchFastModeServiceTiersGuard(${JSON.stringify(filePath)});
process.stdout.write('NO_ERROR');
} catch (error) {
process.stderr.write(String(error?.message ?? error));
process.exit(1);
}
`,
tempRoot,
);

expect(result.status).toBe(1);
expect(result.stderr).toContain('fast mode missing service tiers guard patch target not found');
});

test('prioritizes replacing unsafe fast mode access when guarded code is also present', () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-patch-'));
const filePath = path.join(tempRoot, 'use-is-fast-mode-enabled.js');

fs.writeFileSync(
filePath,
[
'function m(e){return e.serviceTiers.length>0||e.additionalSpeedTiers?.includes(u)===!0}',
'function n(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}',
'',
].join('\n'),
'utf8',
);

const result = runAssemblySnippet(
`
import fs from 'node:fs';
const patchResult = runtime.patchFastModeServiceTiersGuard(${JSON.stringify(filePath)});
process.stdout.write(JSON.stringify({
patchResult,
source: fs.readFileSync(${JSON.stringify(filePath)}, 'utf8'),
}));
`,
tempRoot,
);

expect(result.status).toBe(0);
expect(JSON.parse(result.stdout)).toEqual({
patchResult: [
{
label: 'fast mode missing service tiers guard',
patched: true,
skipped: false,
reason: null,
},
],
source: [
'function m(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}',
'function n(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}',
'',
].join('\n'),
});
});

test('fast mode service-tier guard preserves eligibility semantics', () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-patch-'));

const result = runAssemblySnippet(
`
const isFastModeEligible = new Function(
'model',
'const u = "fast"; const e = model; ' + runtime.fastModeModelServiceTiersPatchReplacement,
);
const cases = [
['serviceTiers omitted', {}, false],
['serviceTiers null', { serviceTiers: null }, false],
['serviceTiers empty', { serviceTiers: [] }, false],
['serviceTiers populated', { serviceTiers: ['priority'] }, true],
[
'additionalSpeedTiers fast',
{ serviceTiers: null, additionalSpeedTiers: ['fast'] },
true,
],
[
'additionalSpeedTiers without fast',
{ serviceTiers: null, additionalSpeedTiers: ['standard'] },
false,
],
];

process.stdout.write(JSON.stringify(
cases.map(([label, model, expected]) => ({
label,
expected,
actual: isFastModeEligible(model),
})),
));
`,
tempRoot,
);

expect(result.status).toBe(0);
expect(JSON.parse(result.stdout)).toEqual([
{ label: 'serviceTiers omitted', expected: false, actual: false },
{ label: 'serviceTiers null', expected: false, actual: false },
{ label: 'serviceTiers empty', expected: false, actual: false },
{ label: 'serviceTiers populated', expected: true, actual: true },
{ label: 'additionalSpeedTiers fast', expected: true, actual: true },
{ label: 'additionalSpeedTiers without fast', expected: false, actual: false },
]);
});

test('hydrates lfs pointer files before copying required runtime helpers', () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-lfs-'));
const filePath = path.join(tempRoot, 'codex');
Expand Down
39 changes: 39 additions & 0 deletions desktop/tests/linux/recovered-bundle.red.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ describe('Recovered Codex bundle RED contract', () => {
const loginRouteBundle = readOutputAsset('login-route-');
const composerBundle = readOutputAsset('composer-');
const appShellBundle = readOutputAsset('app-shell-');
const fastModeBundle = readOutputAsset('use-is-fast-mode-enabled-');
const pluginsPageBundle = fs.readFileSync(
path.join(
outputAssetsRoot,
Expand Down Expand Up @@ -195,7 +196,13 @@ describe('Recovered Codex bundle RED contract', () => {
);
expect(loginRouteBundle).toContain('useExternalBrowser:!0');
expect(composerBundle).toContain('threadGoalObjective');
expect(fastModeBundle).toContain('serviceTiers?.length??0');
expect(summary.patchSummary.modelSettings.results).toEqual([]);
expect(summary.patchSummary.fastMode.results).toEqual(
expect.arrayContaining([
expect.objectContaining({ label: 'fast mode missing service tiers guard' }),
]),
);
expect(pluginsPageBundle).toContain('plugins');
if (pluginInstallFlowBundle != null) {
expect(pluginInstallFlowBundle).toContain('open-in-browser');
Expand Down Expand Up @@ -344,6 +351,7 @@ describe('Recovered Codex bundle RED contract', () => {
pluginsPage?: { results: Array<{ label: string }> };
pluginsCards?: { results: Array<{ label: string }> };
};
fastMode?: { results: Array<{ label: string }> };
};
};

Expand Down Expand Up @@ -379,6 +387,11 @@ describe('Recovered Codex bundle RED contract', () => {
expect.objectContaining({ label: 'plugin install browser fallback opens install url' }),
]),
);
expect(manifest.patchSummary?.fastMode?.results).toEqual(
expect.arrayContaining([
expect.objectContaining({ label: 'fast mode missing service tiers guard' }),
]),
);
});

test('webview index resolves the active renderer entry instead of pinning a full-app bundle name', () => {
Expand Down Expand Up @@ -416,6 +429,32 @@ describe('Recovered Codex bundle RED contract', () => {
expect(readRecoveredAsset('use-collaboration-mode-')).toContain('reasoning_effort');
});

test('fast mode eligibility tolerates older model schemas without service tiers', () => {
const fastModeBundle = readRecoveredAsset('use-is-fast-mode-enabled-');
const assembleScript = readDesktopFile('scripts/assemble-codex-runtime.mjs');
const manifest = JSON.parse(readDesktopFile('recovered/refresh-manifest.json')) as {
patchSummary?: {
fastMode?: { results: Array<{ label: string }> };
};
};

expect(fastModeBundle).toContain('serviceTiers?.length??0');
expect(fastModeBundle).not.toContain('serviceTiers.length>0');
expect(fastModeBundle).not.toMatch(/model\.serviceTiers\.(length|some|map|includes)/);
expect(fastModeBundle).not.toMatch(/serviceTiers\.(length|some|map|includes)/);
expect(assembleScript).toContain('fast mode missing service tiers guard');
expect(assembleScript).toContain('serviceTiers?.length??0');
expect(assembleScript).not.toContain('model.serviceTiers.length');
expect(assembleScript).not.toContain('model.serviceTiers.some');
expect(assembleScript).not.toContain('model.serviceTiers.map');
expect(assembleScript).not.toContain('model.serviceTiers.includes');
expect(manifest.patchSummary?.fastMode?.results).toEqual(
expect.arrayContaining([
expect.objectContaining({ label: 'fast mode missing service tiers guard' }),
]),
);
});

test('plugin page menu patch is skipped when the upstream shell no longer needs it', () => {
const appShell = readRecoveredAsset('app-shell-');
const manifest = JSON.parse(readDesktopFile('recovered/refresh-manifest.json')) as {
Expand Down