fix(server): align Codex Fast with documented model support (#4640)

The prefix allowlist hid Fast for GPT-6 Astra and exposed it for models outside documented Codex Fast support. Use explicit model IDs and avoid claiming a universal usage multiplier.
This commit is contained in:
Mohamed Boudra
2026-09-10 08:42:50 +02:00
committed by GitHub
parent 92504cd525
commit f3917173a9
2 changed files with 98 additions and 8 deletions
@@ -97,6 +97,88 @@ async function createConnectedSession(
}
describe("Codex app-server provider features", () => {
test.each([
"gpt-6-astra",
"gpt-5.6",
"gpt-5.6-sol",
"gpt-5.6-terra",
"gpt-5.6-luna",
"gpt-5.5",
"gpt-5.4",
])("exposes and sends Fast for %s", async (model) => {
const { session, appServer } = await createConnectedSession({ model });
try {
expect(session.features).toContainEqual(
expect.objectContaining({
id: "fast_mode",
value: false,
}),
);
await session.setFeature?.("fast_mode", true);
await session.startTurn("hello");
await expect(appServer.waitForTurnStart()).resolves.toMatchObject({
model,
serviceTier: "fast",
});
} finally {
await session.close();
}
});
test.each([
"gpt-5.3-codex-spark",
"gpt-5.3-codex",
"gpt-5.4-mini",
"gpt-5.4-nano",
"gpt-5.5-pro",
"gpt-5",
"gpt-4.1",
"o3",
"o4-mini",
"gpt-6-unknown",
])("does not expose or restore Fast for %s", async (model) => {
const { session, appServer } = await createConnectedSession({
model,
featureValues: { fast_mode: true },
});
try {
expect(session.features.map((feature) => feature.id)).toEqual(["plan_mode"]);
await expect(session.setFeature?.("fast_mode", true)).rejects.toThrow(
`Codex fast mode is not available for model '${model}'`,
);
await session.startTurn("hello");
await expect(appServer.waitForTurnStart()).resolves.not.toMatchObject({
serviceTier: expect.anything(),
});
} finally {
await session.close();
}
});
test("restores Fast on Astra and preserves it when switching supported models", async () => {
const { session, appServer } = await createConnectedSession({
model: "gpt-6-astra",
featureValues: { fast_mode: true },
});
try {
expect(session.features).toContainEqual(
expect.objectContaining({
id: "fast_mode",
value: true,
}),
);
await session.setModel("gpt-5.6-sol");
await session.setModel("gpt-6-astra");
await session.startTurn("hello");
await expect(appServer.waitForTurnStart()).resolves.toMatchObject({
model: "gpt-6-astra",
serviceTier: "fast",
});
} finally {
await session.close();
}
});
test("features returns fast and plan toggles when supported", async () => {
const { session } = await createConnectedSession();
@@ -105,7 +187,7 @@ describe("Codex app-server provider features", () => {
type: "toggle",
id: "fast_mode",
label: "Fast",
description: "Priority inference at 2x usage",
description: "Priority inference at increased usage",
tooltip: "Toggle fast mode",
icon: "zap",
value: false,
@@ -129,7 +211,7 @@ describe("Codex app-server provider features", () => {
type: "toggle",
id: "fast_mode",
label: "Fast",
description: "Priority inference at 2x usage",
description: "Priority inference at increased usage",
tooltip: "Toggle fast mode",
icon: "zap",
value: true,
@@ -250,7 +332,7 @@ describe("Codex app-server provider features", () => {
type: "toggle",
id: "fast_mode",
label: "Fast",
description: "Priority inference at 2x usage",
description: "Priority inference at increased usage",
tooltip: "Toggle fast mode",
icon: "zap",
value: true,
@@ -1,12 +1,22 @@
import type { AgentFeature, AgentFeatureToggle } from "../agent-sdk-types.js";
const CODEX_FAST_MODE_SUPPORTED_MODEL_PREFIXES = ["gpt-5", "gpt-4.1", "o3", "o4-mini"] as const;
// Codex Fast is distinct from API Priority processing. Keep model support aligned with
// https://developers.openai.com/codex/speed and https://developers.openai.com/codex/models.
const CODEX_FAST_MODE_SUPPORTED_MODELS = new Set([
"gpt-6-astra",
"gpt-5.6",
"gpt-5.6-sol",
"gpt-5.6-terra",
"gpt-5.6-luna",
"gpt-5.5",
"gpt-5.4",
]);
export const CODEX_FAST_MODE_FEATURE: Omit<AgentFeatureToggle, "value"> = {
type: "toggle",
id: "fast_mode",
label: "Fast",
description: "Priority inference at 2x usage",
description: "Priority inference at increased usage",
tooltip: "Toggle fast mode",
icon: "zap",
};
@@ -30,9 +40,7 @@ export function codexModelSupportsFastMode(modelId: string | null | undefined):
if (!normalizedModelId) {
return false;
}
return CODEX_FAST_MODE_SUPPORTED_MODEL_PREFIXES.some(
(prefix) => normalizedModelId === prefix || normalizedModelId.startsWith(prefix),
);
return CODEX_FAST_MODE_SUPPORTED_MODELS.has(normalizedModelId);
}
export function buildCodexFeatures(input: {