mirror of
https://github.com/langgenius/dify.git
synced 2026-06-01 06:28:14 +08:00
119 lines
3.5 KiB
TypeScript
119 lines
3.5 KiB
TypeScript
import type {
|
|
CredentialCandidate,
|
|
CredentialSelectionInput,
|
|
CredentialSlot,
|
|
} from '@dify/contracts/enterprise/types.gen'
|
|
|
|
export type RuntimeCredentialBindingSelections = Record<string, string>
|
|
|
|
export type RuntimeCredentialSelectOption = {
|
|
value: string
|
|
label: string
|
|
}
|
|
|
|
const PROVIDER_DISPLAY_NAMES: Record<string, string> = {
|
|
azure_openai: 'Azure OpenAI',
|
|
bedrock: 'Amazon Bedrock',
|
|
gemini: 'Gemini',
|
|
google: 'Google',
|
|
openai: 'OpenAI',
|
|
vertex_ai: 'Vertex AI',
|
|
volcengine_maas: 'Volcengine',
|
|
}
|
|
|
|
function providerSlug(providerId?: string) {
|
|
const parts = providerId?.split('/').filter(Boolean) ?? []
|
|
return parts[parts.length - 1] ?? ''
|
|
}
|
|
|
|
function titleCaseProviderName(value: string) {
|
|
return value
|
|
.split(/[-_]/)
|
|
.filter(Boolean)
|
|
.map(part => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
.join(' ')
|
|
}
|
|
|
|
export function runtimeCredentialSlotKey(slot: CredentialSlot) {
|
|
return [slot.providerId ?? '', slot.category ?? ''].join(':')
|
|
}
|
|
|
|
export function runtimeCredentialProviderName(providerId?: string) {
|
|
const slug = providerSlug(providerId)
|
|
if (!slug)
|
|
return ''
|
|
|
|
return PROVIDER_DISPLAY_NAMES[slug.toLowerCase()] ?? titleCaseProviderName(slug)
|
|
}
|
|
|
|
function runtimeCredentialCandidateLabel(candidate: CredentialCandidate) {
|
|
const fallback = candidate.credentialId ?? ''
|
|
const rawLabel = candidate.displayName?.trim() || fallback
|
|
const providerId = candidate.providerId?.trim()
|
|
if (!providerId)
|
|
return rawLabel
|
|
|
|
const providerSuffixes = [
|
|
` · ${providerId}`,
|
|
` - ${providerId}`,
|
|
` (${providerId})`,
|
|
]
|
|
const label = providerSuffixes.reduce((nextLabel, suffix) => {
|
|
return nextLabel.endsWith(suffix)
|
|
? nextLabel.slice(0, -suffix.length).trim()
|
|
: nextLabel
|
|
}, rawLabel)
|
|
|
|
return label || fallback
|
|
}
|
|
|
|
export function runtimeCredentialCandidateOptions(slot: CredentialSlot): RuntimeCredentialSelectOption[] {
|
|
return (slot.candidates ?? [])
|
|
.filter(candidate => candidate.credentialId)
|
|
.map(candidate => ({
|
|
value: candidate.credentialId!,
|
|
label: runtimeCredentialCandidateLabel(candidate),
|
|
}))
|
|
}
|
|
|
|
export function hasMissingRequiredRuntimeCredentialBinding(_slot: CredentialSlot, selectedValue?: string) {
|
|
return !selectedValue
|
|
}
|
|
|
|
export function selectedRuntimeCredentialSelections(
|
|
slots: CredentialSlot[],
|
|
manualBindings: RuntimeCredentialBindingSelections,
|
|
): RuntimeCredentialBindingSelections {
|
|
const next: RuntimeCredentialBindingSelections = {}
|
|
for (const slot of slots) {
|
|
const slotKey = runtimeCredentialSlotKey(slot)
|
|
const candidates = runtimeCredentialCandidateOptions(slot)
|
|
const existing = manualBindings[slotKey]
|
|
if (existing && candidates.some(candidate => candidate.value === existing))
|
|
next[slotKey] = existing
|
|
else if (candidates.length === 1 && candidates[0])
|
|
next[slotKey] = candidates[0].value
|
|
}
|
|
return next
|
|
}
|
|
|
|
export function selectedDeploymentRuntimeCredentials(
|
|
slots: CredentialSlot[],
|
|
selections: RuntimeCredentialBindingSelections,
|
|
): CredentialSelectionInput[] {
|
|
return slots
|
|
.map((slot): CredentialSelectionInput | undefined => {
|
|
const slotKey = runtimeCredentialSlotKey(slot)
|
|
const selectedValue = selections[slotKey]
|
|
if (!slotKey || !selectedValue)
|
|
return undefined
|
|
|
|
return {
|
|
providerId: slot.providerId,
|
|
category: slot.category,
|
|
credentialId: selectedValue,
|
|
}
|
|
})
|
|
.filter((binding): binding is CredentialSelectionInput => Boolean(binding))
|
|
}
|