(provider: string, modelId: string, modelDef: ModelDefinition | null)
| 86 | } |
| 87 | |
| 88 | function inferReasoning(provider: string, modelId: string, modelDef: ModelDefinition | null): InferReasoningResult { |
| 89 | // Builtin catalog models: trust capabilities array exclusively. |
| 90 | // Custom (builtin=false) or unlisted models: also check name heuristic as fallback because |
| 91 | // auto-saved custom model entries carry only capabilities:['chat'] even for reasoning models. |
| 92 | const reasoning = |
| 93 | modelDef?.capabilities.includes('reasoning') || (!modelDef?.builtin && isReasoningModel(provider, modelId)) |
| 94 | |
| 95 | if (!reasoning) return { reasoning: false, compat: undefined } |
| 96 | |
| 97 | const thinkingCompat = getThinkingCompat(provider, modelId) |
| 98 | if (Object.keys(thinkingCompat).length === 0) { |
| 99 | return { reasoning: true, compat: undefined } |
| 100 | } |
| 101 | |
| 102 | // thinkingLevelMap belongs on the Model top-level (for clampThinkingLevel), |
| 103 | // while thinkingFormat/supportsReasoningEffort belong in compat (for the provider). |
| 104 | const { thinkingLevelMap, ...compatFields } = thinkingCompat |
| 105 | return { |
| 106 | reasoning: true, |
| 107 | compat: Object.keys(compatFields).length > 0 ? compatFields : undefined, |
| 108 | thinkingLevelMap: thinkingLevelMap as PiModel<PiApi>['thinkingLevelMap'], |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | export function buildPiModel(config: PiModelConfig, options?: BuildPiModelOptions): PiModel<PiApi> { |
| 113 | const providerDef = BUILTIN_PROVIDERS.find((p) => p.id === config.provider) |
no test coverage detected