export const GPT56_CAPABILITIES = [ { id: "luna", label: "Luna", modelId: "gpt-5.6-luna" }, { id: "terra", label: "Terra", modelId: "gpt-5.6-terra" }, { id: "sol", label: "Sol", modelId: "gpt-5.6-sol" }, ] as const; export const GPT56_THINKING_LEVELS = [ { id: "off", label: "Off" }, { id: "minimal", label: "Minimal" }, { id: "low", label: "Low" }, { id: "medium", label: "Medium" }, { id: "high", label: "High" }, { id: "xhigh", label: "XHigh" }, { id: "max", label: "Max" }, ] as const; export type Gpt56CapabilityId = (typeof GPT56_CAPABILITIES)[number]["id"]; export type Gpt56ThinkingLevel = (typeof GPT56_THINKING_LEVELS)[number]["id"]; export interface DiscoverableModel { id: string; provider: string; reasoning: boolean; thinkingLevelMap?: Partial>; } export interface Gpt56Profile { providerId: string; capability: Gpt56CapabilityId; capabilityLabel: string; modelId: string; thinkingLevel: Gpt56ThinkingLevel; thinkingLabel: string; } export function getSupportedThinkingLevels( model: DiscoverableModel, ): Gpt56ThinkingLevel[] { if (!model.reasoning) return ["off"]; return GPT56_THINKING_LEVELS.flatMap(({ id }) => { const mapped = model.thinkingLevelMap?.[id]; if (mapped === null) return []; if ((id === "xhigh" || id === "max") && mapped === undefined) return []; return [id]; }); } export function discoverGpt56Profiles( models: readonly DiscoverableModel[], providerId: string, ): Gpt56Profile[] { return GPT56_CAPABILITIES.flatMap((capability) => { const model = models.find( (candidate) => candidate.provider === providerId && candidate.id.toLowerCase() === capability.modelId, ); if (!model) return []; const supported = new Set(getSupportedThinkingLevels(model)); return GPT56_THINKING_LEVELS.flatMap((thinking) => supported.has(thinking.id) ? [ { providerId, capability: capability.id, capabilityLabel: capability.label, modelId: model.id, thinkingLevel: thinking.id, thinkingLabel: thinking.label, }, ] : [], ); }); } export function getAvailableCapabilities( profiles: readonly Gpt56Profile[], ): Gpt56CapabilityId[] { return GPT56_CAPABILITIES.flatMap((capability) => profiles.some((profile) => profile.capability === capability.id) ? [capability.id] : [], ); } export function wrapProfileIndex(index: number, length: number): number { if (length <= 0) return 0; return ((index % length) + length) % length; } function closestThinkingIndex( profiles: readonly Gpt56Profile[], candidateIndexes: readonly number[], requestedLevel: string, ): number { const exact = candidateIndexes.find( (index) => profiles[index].thinkingLevel === requestedLevel, ); if (exact !== undefined) return exact; const requestedIndex = GPT56_THINKING_LEVELS.findIndex( (thinking) => thinking.id === requestedLevel, ); if (requestedIndex >= 0) { for (let i = requestedIndex; i < GPT56_THINKING_LEVELS.length; i++) { const level = GPT56_THINKING_LEVELS[i].id; const match = candidateIndexes.find( (index) => profiles[index].thinkingLevel === level, ); if (match !== undefined) return match; } for (let i = requestedIndex - 1; i >= 0; i--) { const level = GPT56_THINKING_LEVELS[i].id; const match = candidateIndexes.find( (index) => profiles[index].thinkingLevel === level, ); if (match !== undefined) return match; } } return candidateIndexes[0] ?? 0; } export function findInitialProfileIndex( profiles: readonly Gpt56Profile[], modelId: string | undefined, thinkingLevel: string, ): number { if (profiles.length === 0) return 0; const exact = profiles.findIndex( (profile) => profile.modelId === modelId && profile.thinkingLevel === thinkingLevel, ); if (exact >= 0) return exact; const sameModel = profiles.flatMap((profile, index) => profile.modelId === modelId ? [index] : [], ); if (sameModel.length > 0) { return closestThinkingIndex(profiles, sameModel, thinkingLevel); } const capabilities = getAvailableCapabilities(profiles); const preferredCapability = capabilities[capabilities.length - 1]; const preferred = profiles.flatMap((profile, index) => profile.capability === preferredCapability ? [index] : [], ); return closestThinkingIndex(profiles, preferred, thinkingLevel); } export function moveThinkingIndex( profiles: readonly Gpt56Profile[], currentIndex: number, delta: number, ): number { if (profiles.length === 0) return 0; const normalizedIndex = wrapProfileIndex(currentIndex, profiles.length); const current = profiles[normalizedIndex]; const groupIndexes = profiles.flatMap((profile, index) => profile.capability === current.capability ? [index] : [], ); const groupPosition = groupIndexes.indexOf(normalizedIndex); return groupIndexes[wrapProfileIndex(groupPosition + delta, groupIndexes.length)]; } export function jumpCapabilityIndex( profiles: readonly Gpt56Profile[], currentIndex: number, delta: number, ): number { if (profiles.length === 0) return 0; const current = profiles[wrapProfileIndex(currentIndex, profiles.length)]; const capabilities = getAvailableCapabilities(profiles); const capabilityIndex = capabilities.indexOf(current.capability); const targetCapability = capabilities[ wrapProfileIndex(capabilityIndex + delta, capabilities.length) ]; const targetIndexes = profiles.flatMap((profile, index) => profile.capability === targetCapability ? [index] : [], ); return closestThinkingIndex(profiles, targetIndexes, current.thinkingLevel); } export function findProfile( profiles: readonly Gpt56Profile[], capability: string, thinkingLevel: string, ): Gpt56Profile | undefined { const normalizedCapability = capability.toLowerCase(); const normalizedThinking = thinkingLevel.toLowerCase(); return profiles.find( (profile) => profile.capability === normalizedCapability && profile.thinkingLevel === normalizedThinking, ); }