diff --git a/packages/client-runtime/src/state/threadExecution.test.ts b/packages/client-runtime/src/state/threadExecution.test.ts index fd03b06b32017..c02e2c13fefbe 100644 --- a/packages/client-runtime/src/state/threadExecution.test.ts +++ b/packages/client-runtime/src/state/threadExecution.test.ts @@ -24,10 +24,10 @@ import { deriveLatestThreadRun, deriveProviderSubagentStatus, deriveResumableRunId, + formatModelSelectionEffort, deriveRunlessWorkStartedAt, deriveThreadActivityRun, deriveThreadRuntime, - formatModelSelectionEffort, isBackgroundWorkStopPending, presentPendingBackgroundWork, presentProviderGoal, @@ -476,6 +476,38 @@ describe("provider-reported model selection", () => { }); describe("formatModelSelectionEffort", () => { + it("finds the catalog model when the selection names it by display name or alias", () => { + const selection = { + ...v2Projection.thread.modelSelection, + model: "GPT-6 Luna", + options: [{ id: "reasoning_effort", value: "medium" }], + }; + const models = [ + { + slug: "custom:GPT-6 Luna-12", + name: "GPT-6 Luna", + aliases: ["Luna-12"], + isCustom: true, + capabilities: { + optionDescriptors: [ + { + id: "reasoning_effort", + label: "Reasoning", + type: "select" as const, + options: [ + { id: "medium", label: "Medium" }, + { id: "high", label: "High" }, + ], + }, + ], + }, + }, + ]; + + expect(formatModelSelectionEffort(selection, models)).toBe("Medium"); + expect(formatModelSelectionEffort({ ...selection, model: "Luna-12" }, models)).toBe("Medium"); + }); + it("labels an old Ultracode effort by the effort it runs at", () => { const models = [ { diff --git a/packages/client-runtime/src/state/threadExecution.ts b/packages/client-runtime/src/state/threadExecution.ts index 6b260d7224c20..2787122fba139 100644 --- a/packages/client-runtime/src/state/threadExecution.ts +++ b/packages/client-runtime/src/state/threadExecution.ts @@ -166,12 +166,27 @@ export const REASONING_EFFORT_OPTION_IDS: ReadonlyArray = [ "thinking_level", ]; +function findSelectionCatalogModel( + models: ReadonlyArray, + model: string, +): ServerProviderModel | undefined { + const name = model.trim().toLowerCase(); + return ( + models.find((candidate) => candidate.slug === model) ?? + models.find( + (candidate) => + candidate.name.trim().toLowerCase() === name || + candidate.aliases?.some((alias) => alias.trim().toLowerCase() === name), + ) + ); +} + export function formatModelSelectionEffort( selection: ModelSelection, models: ReadonlyArray = [], reportedSelection?: ModelSelection | null, ): string | null { - const caps = models.find((model) => model.slug === selection.model)?.capabilities; + const caps = findSelectionCatalogModel(models, selection.model)?.capabilities; if (!caps) return null; const options = withLegacyUltracodeEffort(caps.optionDescriptors, selection.options); const current = options ? { ...selection, options } : selection;