Skip to content
Merged
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
18 changes: 15 additions & 3 deletions apps/ade-cli/src/tuiClient/__tests__/appInput.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1203,7 +1203,7 @@ describe("interface draft setup", () => {
]);
});

it("shows the product-facing Sol effort ladder without internal max", () => {
it("shows the complete GPT-5.6 effort ladders from runtime and registry metadata", () => {
const modelState = initialModelState("chat");
const models = [{
id: "gpt-5.6-sol",
Expand All @@ -1214,7 +1214,19 @@ describe("interface draft setup", () => {
.map((effort) => ({ effort, description: effort })),
}];

expect(modelReasoningEfforts(modelState, models)).toEqual(["low", "medium", "high", "xhigh", "ultra"]);
expect(modelReasoningEfforts(modelState, models)).toEqual(["low", "medium", "high", "xhigh", "max", "ultra"]);
expect(modelReasoningEfforts({
...modelState,
model: "gpt-5.6-terra",
modelId: "openai/gpt-5.6-terra",
displayName: "GPT-5.6 Terra",
}, [])).toEqual(["low", "medium", "high", "xhigh", "max", "ultra"]);
expect(modelReasoningEfforts({
...modelState,
model: "gpt-5.6-luna",
modelId: "openai/gpt-5.6-luna",
displayName: "GPT-5.6 Luna",
}, [])).toEqual(["low", "medium", "high", "xhigh", "max"]);
expect(buildSetupRows({
modelState,
models,
Expand All @@ -1224,7 +1236,7 @@ describe("interface draft setup", () => {
interfaceEditable: true,
}).find((row) => row.kind === "reasoning")).toMatchObject({
value: "Light",
detail: "Light, Medium, High, Extra High, Ultra",
detail: "Light, Medium, High, Extra High, Max, Ultra",
});
});

Expand Down
15 changes: 5 additions & 10 deletions apps/ade-cli/src/tuiClient/modelState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { theme } from "./theme";
import type { AdeCodeInterfaceMode, AdeCodeModelState, AdeCodeProvider, SetupPaneRow, SetupPaneRowKind } from "./types";
import { normalizeProvider, providerLabel } from "./providerMetadata";

export const EFFORTS = ["low", "medium", "high", "xhigh", "ultra"];
export const EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"];
export const CODEX_PRESETS = ["default", "edit", "plan", "full-auto", "config-toml"] as const;
export const CLAUDE_PERMISSION_OPTIONS = ["default", "auto", "plan", "acceptEdits", "bypassPermissions"] as const;
export const OPENCODE_PERMISSION_OPTIONS = ["plan", "edit", "full-auto", "config-toml"] as const;
Expand Down Expand Up @@ -69,10 +69,9 @@ export function cliProviderForModelStateProvider(provider: AdeCodeProvider): Cli

function firstReasoningEffortForModel(model: AgentChatModelInfo | null | undefined, provider: AdeCodeProvider): string | null {
const modelId = `${model?.modelId ?? ""} ${model?.id ?? ""} ${model?.displayName ?? ""}`.toLowerCase();
const isGpt56CodexModel = provider === "codex" && /gpt-5\.6-(?:sol|terra|luna)/.test(modelId);
const efforts = model?.reasoningEfforts
?.map((entry) => entry.effort)
.filter((effort) => Boolean(effort) && (!isGpt56CodexModel || effort !== "max")) ?? [];
.filter(Boolean) ?? [];
const advertisedDefault = model?.defaultReasoningEffort?.trim().toLowerCase() ?? null;
if (modelId.includes("fable") && efforts.includes("high")) return "high";
if (advertisedDefault && efforts.includes(advertisedDefault)) return advertisedDefault;
Expand Down Expand Up @@ -285,13 +284,8 @@ export function modelReasoningEfforts(modelState: AdeCodeModelState, models: Age
const model = models.find((entry) => entry.id === modelState.modelId || entry.modelId === modelState.modelId);
const fromModel = model?.reasoningEfforts?.map((entry) => entry.effort).filter(Boolean) ?? [];
const descriptor = modelState.modelId ? getModelById(modelState.modelId) : undefined;
const isGpt56CodexModel = modelState.provider === "codex"
&& /gpt-5\.6-(?:sol|terra|luna)/i.test(`${descriptor?.providerModelId ?? ""} ${modelState.model}`);
const visibleEfforts = (efforts: string[]) => isGpt56CodexModel
? efforts.filter((effort) => effort !== "max")
: efforts;
if (fromModel.length) return visibleEfforts(fromModel);
if (descriptor?.reasoningTiers?.length) return visibleEfforts(descriptor.reasoningTiers);
if (fromModel.length) return fromModel;
if (descriptor?.reasoningTiers?.length) return descriptor.reasoningTiers;
return modelState.provider === "codex" ? EFFORTS : [];
}

Expand All @@ -307,6 +301,7 @@ export function reasoningEffortDisplayLabel(
if (effort === "medium") return "Medium";
if (effort === "high") return "High";
if (effort === "xhigh") return "Extra High";
if (effort === "max") return "Max";
if (effort === "ultra") return "Ultra";
return effort;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15565,16 +15565,15 @@ describe("createAgentChatService", () => {
expect.objectContaining({ effort: "medium" }),
expect.objectContaining({ effort: "high" }),
expect.objectContaining({ effort: "xhigh" }),
expect.objectContaining({ effort: "max" }),
expect.objectContaining({ effort: "ultra" }),
],
serviceTiers: ["fast"],
});
expect(models[1]).toMatchObject({ isDefault: false, defaultReasoningEffort: "medium" });
expect(models[2]?.reasoningEfforts?.map((entry) => entry.effort)).toEqual([
"low", "medium", "high", "xhigh",
"low", "medium", "high", "xhigh", "max",
]);
expect(models.slice(0, 3).flatMap((model) => model.reasoningEfforts ?? []))
.not.toContainEqual(expect.objectContaining({ effort: "max" }));
expect(models[3]?.isDefault).toBe(false);

const aggregate = await service.getAvailableModels({});
Expand Down
17 changes: 1 addition & 16 deletions apps/desktop/src/main/services/chat/agentChatService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2143,21 +2143,6 @@ const CLAUDE_REASONING_EFFORTS: Array<{ effort: string; description: string }> =

const KNOWN_CLAUDE_EFFORTS = new Set(CLAUDE_REASONING_EFFORTS.map((e) => e.effort));

function isGpt56CodexDescriptor(descriptor: ModelDescriptor): boolean {
return /^gpt-5\.6-(?:sol|terra|luna)$/i.test(descriptor.providerModelId);
}

function visibleCodexReasoningEfforts(
descriptor: ModelDescriptor,
efforts: Array<{ effort: string; description: string }>,
): Array<{ effort: string; description: string }> {
if (!isGpt56CodexDescriptor(descriptor)) return efforts;
// Codex Desktop keeps `max` behind an opt-in model-feature flag. ADE does
// not expose that flag, so omit only that internal/optional tier while still
// retaining unknown app-server values for forward compatibility.
return efforts.filter((entry) => entry.effort !== "max");
}

function codexModelInfoFromDescriptor(
descriptor: ModelDescriptor,
overrides?: Partial<Pick<AgentChatModelInfo, "description" | "isDefault" | "reasoningEfforts" | "defaultReasoningEffort" | "serviceTiers">>,
Expand All @@ -2170,7 +2155,7 @@ function codexModelInfoFromDescriptor(
displayName: descriptor.displayName,
description: overrides?.description ?? describeCodexModel(descriptor.displayName),
isDefault: overrides?.isDefault ?? descriptor.id === DEFAULT_CODEX_DESCRIPTOR?.id,
reasoningEfforts: visibleCodexReasoningEfforts(descriptor, advertisedReasoningEfforts),
reasoningEfforts: advertisedReasoningEfforts,
defaultReasoningEffort: overrides?.defaultReasoningEffort
?? descriptor.defaultReasoningEffort
?? null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ describe("ReasoningEffortPicker", () => {
expect(trigger.textContent).toContain("ULTRA");
await user.click(trigger);

expect(screen.getAllByRole("radio")).toHaveLength(5);
expect(screen.queryByRole("radio", { name: "Max" })).toBeNull();
expect(screen.getAllByRole("radio")).toHaveLength(6);
expect(screen.getByRole("radio", { name: "Max" })).toBeTruthy();
expect(screen.getByRole("radio", { name: "Light" })).toBeTruthy();
expect(screen.getByRole("radio", { name: "Ultra" })).toBeTruthy();
expect(screen.getByText(/automatically delegates work to multiple agents/i)).toBeTruthy();
Expand Down Expand Up @@ -317,7 +317,7 @@ describe("ReasoningEffortPicker", () => {
firePointer("pointerup", 236);

expect(track!.hasAttribute("data-dragging")).toBe(false);
expect(track!.style.getPropertyValue("--reasoning-slider-thumb-position")).toContain("75%");
expect(track!.style.getPropertyValue("--reasoning-slider-thumb-position")).toContain("60%");
expect(releasePointerCapture).toHaveBeenCalledWith(7);
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledWith("xhigh");
Expand Down Expand Up @@ -375,7 +375,7 @@ describe("ReasoningEffortPicker", () => {

expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledWith("xhigh");
expect(track!.style.getPropertyValue("--reasoning-slider-thumb-position")).toContain("75%");
expect(track!.style.getPropertyValue("--reasoning-slider-thumb-position")).toContain("60%");
expect(trigger.getAttribute("aria-expanded")).toBe("true");
});

Expand Down
Loading