import type { ModelMetadata } from "../connected-providers-cache" import type { ModelCapabilities } from "./types" function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value) } function readNumber(value: unknown): number | undefined { return typeof value === "number" ? value : undefined } function readStringArray(value: unknown): string[] | undefined { if (!Array.isArray(value)) { return undefined } const strings = value.filter((item): item is string => typeof item === "string") return strings.length > 0 ? strings : undefined } function normalizeVariantKeys(value: unknown): string[] | undefined { const arrayVariants = readStringArray(value) if (arrayVariants) { return arrayVariants.map((variant) => variant.toLowerCase()) } if (!isRecord(value)) { return undefined } const variants = Object.keys(value).map((variant) => variant.toLowerCase()) return variants.length > 0 ? variants : undefined } function readModalityKeys(value: unknown): string[] | undefined { const stringArray = readStringArray(value) if (stringArray) { return stringArray.map((entry) => entry.toLowerCase()) } if (!isRecord(value)) { return undefined } const enabled = Object.entries(value) .filter(([, supported]) => supported === true) .map(([modality]) => modality.toLowerCase()) return enabled.length > 0 ? enabled : undefined } function normalizeModalities(value: unknown): ModelCapabilities["modalities"] | undefined { if (!isRecord(value)) { return undefined } const input = readModalityKeys(value.input) const output = readModalityKeys(value.output) if (!input && !output) { return undefined } return { ...(input ? { input } : {}), ...(output ? { output } : {}), } } function readRuntimeModelCapabilities( runtimeModel: Record | undefined, ): Record | undefined { return isRecord(runtimeModel?.capabilities) ? runtimeModel.capabilities : undefined } function readRuntimeModelBoolean( runtimeModel: Record | undefined, keys: string[], ): boolean | undefined { const runtimeCapabilities = readRuntimeModelCapabilities(runtimeModel) for (const key of keys) { const value = runtimeModel?.[key] if (typeof value === "boolean") { return value } const capabilityValue = runtimeCapabilities?.[key] if (typeof capabilityValue === "boolean") { return capabilityValue } } return undefined } export function readRuntimeModel( runtimeModel: ModelMetadata | Record | undefined, ): Record | undefined { return isRecord(runtimeModel) ? runtimeModel : undefined } export function readRuntimeModelVariants( runtimeModel: Record | undefined, ): string[] | undefined { const rootVariants = normalizeVariantKeys(runtimeModel?.variants) if (rootVariants) { return rootVariants } return normalizeVariantKeys(readRuntimeModelCapabilities(runtimeModel)?.variants) } export function readRuntimeModelModalities( runtimeModel: Record | undefined, ): ModelCapabilities["modalities"] | undefined { const rootModalities = normalizeModalities(runtimeModel?.modalities) if (rootModalities) { return rootModalities } const runtimeCapabilities = readRuntimeModelCapabilities(runtimeModel) return ( normalizeModalities(runtimeCapabilities?.modalities) ?? normalizeModalities(runtimeCapabilities) ) } export function readRuntimeModelReasoningSupport( runtimeModel: Record | undefined, ): boolean | undefined { return readRuntimeModelBoolean(runtimeModel, ["reasoning"]) } export function readRuntimeModelThinkingSupport( runtimeModel: Record | undefined, ): boolean | undefined { const capabilityValue = readRuntimeModelReasoningSupport(runtimeModel) if (capabilityValue !== undefined) { return capabilityValue } const thinkingSupport = readRuntimeModelBoolean(runtimeModel, ["thinking", "supportsThinking"]) if (thinkingSupport !== undefined) { return thinkingSupport } const runtimeCapabilities = readRuntimeModelCapabilities(runtimeModel) for (const key of ["thinking", "supportsThinking"] as const) { const value = runtimeCapabilities?.[key] if (typeof value === "boolean") { return value } } return undefined } export function readRuntimeModelTemperatureSupport( runtimeModel: Record | undefined, ): boolean | undefined { return readRuntimeModelBoolean(runtimeModel, ["temperature"]) } export function readRuntimeModelTopPSupport( runtimeModel: Record | undefined, ): boolean | undefined { return readRuntimeModelBoolean(runtimeModel, ["topP", "top_p"]) } export function readRuntimeModelToolCallSupport( runtimeModel: Record | undefined, ): boolean | undefined { return readRuntimeModelBoolean(runtimeModel, ["toolCall", "tool_call", "toolcall"]) } export function readRuntimeModelLimitOutput( runtimeModel: Record | undefined, ): number | undefined { const limit = isRecord(runtimeModel?.limit) ? runtimeModel.limit : readRuntimeModelCapabilities(runtimeModel)?.limit if (!isRecord(limit)) { return undefined } return readNumber(limit.output) }