feat: use managed model capabilities for reasoning and image input

This commit is contained in:
2026-09-12 21:37:18 +08:00
parent e7701d1f2c
commit 26cbb29aa9
29 changed files with 652 additions and 271 deletions

View File

@@ -35,8 +35,10 @@ export const PI_PROVIDER_APIS = [
] as const;
export type PiProviderApi = (typeof PI_PROVIDER_APIS)[number];
import { unknownManagedModelCapability } from '../../../shared/managed-model-capabilities';
export interface PiProviderModelDescriptor {
managedCapability?: import('../../../shared/managed-model-capabilities').ManagedModelCapability;
id: string;
name: string;
input: Array<'text' | 'image'>;
@@ -119,6 +121,7 @@ export async function buildPiProviderCatalogFromProviderService(
}
export interface PiProviderSelection {
managedCapability?: import('../../../shared/managed-model-capabilities').ManagedModelCapability;
accountId: string;
runtimeProviderId: string;
modelId: string;
@@ -258,7 +261,7 @@ function normalizeModelId(rawModelId: string | undefined, account: ProviderAccou
const unqualified = modelId.startsWith(runtimePrefix)
? modelId.slice(runtimePrefix.length)
: modelId;
return account.id === NIANCODE_USER_MODEL_ACCOUNT_ID
return account.id === NIANCODE_USER_MODEL_ACCOUNT_ID && !account.metadata?.worksSquareModelCapabilitiesV2
? normalizeImportedUserModelId(unqualified)
: unqualified;
}
@@ -306,41 +309,52 @@ function modelDescriptor(
const backend = backendModels.get(modelId);
const profile = getImportedModelProfile(modelId);
const serverCapability = account.metadata?.worksSquareModelCapabilities?.[modelId];
const managed = account.id === 'niancode-user-models'
? account.metadata?.worksSquareModelCapabilitiesV2?.models[modelId] ?? unknownManagedModelCapability()
: undefined;
const backendInput = Array.isArray(backend?.input)
? backend.input.filter((input): input is 'text' | 'image' => input === 'text' || input === 'image')
: [];
const supportsImage = Boolean(
const supportsImage = managed ? managed.inputModalities?.includes('image') === true : Boolean(
summary?.supportsVision
|| profile?.modalities.input.includes('image')
|| backendInput.includes('image'),
);
const contextWindow = finitePositiveInteger(summary?.contextWindow)
const contextWindow = finitePositiveInteger(managed?.limits?.contextWindow)
?? finitePositiveInteger(summary?.contextWindow)
?? finitePositiveInteger(profile?.limit?.context)
?? finitePositiveInteger(backend?.contextWindow);
const maxOutputTokens = finitePositiveInteger(profile?.limit?.output)
const maxOutputTokens = finitePositiveInteger(managed?.limits?.maxOutputTokens)
?? finitePositiveInteger(profile?.limit?.output)
?? finitePositiveInteger(backend?.maxTokens);
return {
id: modelId,
name: summary?.name || (typeof backend?.name === 'string' && backend.name.trim()) || modelId,
input: supportsImage ? ['text', 'image'] : ['text'],
reasoning: serverCapability
...(managed ? { managedCapability: managed } : {}),
reasoning: managed ? managed.reasoning.supported === true : serverCapability
? serverCapability.reasoningEfforts.length > 0
: summary?.supportsReasoning === true
|| profile?.pi?.reasoning === true
|| backend?.reasoning === true,
...(contextWindow ? { contextWindow } : {}),
...(maxOutputTokens ? { maxOutputTokens } : {}),
...(compat || profile?.pi?.compat || enforcedCompat || serverCapability
...(compat || profile?.pi?.compat || enforcedCompat || serverCapability || managed
? {
compat: {
...compat,
...profile?.pi?.compat,
...enforcedCompat,
...(serverCapability ? { supportsReasoningEffort: true } : {}),
...(managed ? {
supportsReasoningEffort: false,
thinkingFormat: managed.reasoning.controlFormat ?? undefined,
requiresReasoningContentOnAssistantMessages: managed.reasoning.controlFormat !== null,
} : {}),
},
}
: {}),
...(serverCapability
...(managed ? {} : serverCapability
? { thinkingLevelMap: thinkingLevelMapForImportedModelCapability(serverCapability) }
: profile?.pi?.thinkingLevelMap
? { thinkingLevelMap: { ...profile.pi.thinkingLevelMap } }
@@ -498,6 +512,7 @@ export function selectPiProviderModel(
modelId: model.id,
thinkingLevel: modelRef.thinkingLevel,
input: [...model.input],
...(model.managedCapability ? { managedCapability: model.managedCapability } : {}),
...(model.contextWindow ? { contextWindow: model.contextWindow } : {}),
...(model.maxOutputTokens ? { maxOutputTokens: model.maxOutputTokens } : {}),
};