import type { Parameter, SelectItem } from '#types'; export function normalizeKnowledgeIds(data: Record): string[] { if (Array.isArray(data.knowledgeIds)) { const seen = new Set(); return data.knowledgeIds.flatMap((id: unknown) => { if (id === null || id === undefined) return []; const value = String(id).trim(); if (!value || seen.has(value)) return []; seen.add(value); return [value]; }); } return data.knowledgeId === null || data.knowledgeId === undefined || String(data.knowledgeId).trim() === '' ? [] : [String(data.knowledgeId).trim()]; } export function toggleKnowledgeId( selectedIds: Array, value: number | string, ): string[] { const key = String(value); return selectedIds.some((id) => String(id) === key) ? selectedIds.filter((id) => String(id) !== key).map(String) : [...selectedIds.map(String), key]; } export function applyEmbeddingCompatibility( items: SelectItem[], selectedIds: Array, ): SelectItem[] { const selectedKeys = new Set(selectedIds.map(String)); const normalizedItems = items.map((item) => ({ ...item, value: String(item.value) })); for (const selectedId of selectedIds.map(String)) { if (!normalizedItems.some((item) => String(item.value) === selectedId)) { normalizedItems.push({ value: selectedId, label: `已失效知识库(${selectedId})`, selectable: true, disabledReason: '知识库不存在或已无权限,仅可移除', }); } } const firstSelected = normalizedItems.find( (item) => String(item.value) === String(selectedIds[0]), ); if (!firstSelected) return normalizedItems; const vectorState = (item: SelectItem): 'available' | 'unavailable' | 'unknown' => { if (item.vectorStoreEnabled === false) return 'unavailable'; if ( item.vectorStoreEnabled === true && item.embeddingModelId !== null && item.embeddingModelId !== undefined && item.embeddingDimension !== null && item.embeddingDimension !== undefined ) { return 'available'; } return 'unknown'; }; const firstState = vectorState(firstSelected); const isCompatible = (item: SelectItem) => firstState === 'available' && vectorState(item) === 'available' && firstSelected.embeddingModelId === item.embeddingModelId && firstSelected.embeddingDimension === item.embeddingDimension; return normalizedItems.map((item) => { if (selectedKeys.has(String(item.value))) { if (item.disabledReason) return item; const itemState = vectorState(item); if (itemState === 'unavailable') { return { ...item, selectable: true, disabledReason: '未启用向量检索,仅可移除', }; } if ( firstState === 'available' && itemState === 'available' && !isCompatible(item) ) { return { ...item, selectable: true, disabledReason: '与首个知识库的 Embedding 配置不一致,仅可移除', }; } return { ...item, selectable: true, disabledReason: undefined }; } const itemState = vectorState(item); if (firstSelected.disabledReason || firstState === 'unavailable') { return { ...item, selectable: false, disabledReason: '请先移除未启用向量检索的知识库', }; } if (itemState === 'unavailable') { return { ...item, selectable: false, disabledReason: '未启用向量检索', }; } if (firstState === 'unknown' || itemState === 'unknown') { return { ...item, selectable: true, disabledReason: undefined }; } return isCompatible(item) ? { ...item, selectable: true, disabledReason: undefined } : { ...item, selectable: false, disabledReason: '与首个知识库的 Embedding 模型或向量维度不一致', }; }); } export function buildKnowledgeSelectItems( items: SelectItem[], selectedIds: Array, reloadItem?: SelectItem, ): SelectItem[] { const compatibleItems = applyEmbeddingCompatibility(items, selectedIds); return reloadItem ? [ ...compatibleItems, { ...reloadItem, selectable: true, disabledReason: undefined }, ] : compatibleItems; } const locked = (parameter: Parameter): Parameter => ({ ...parameter, nameDisabled: true, dataTypeDisabled: true, deleteDisabled: true, }); const expectedOutputDefs: Parameter[] = [ locked({ id: 'knowledge_documents', name: 'documents', dataType: 'Array', addChildDisabled: true, children: [ locked({ id: 'knowledge_documents_title', name: 'title', dataType: 'String' }), locked({ id: 'knowledge_documents_content', name: 'content', dataType: 'String' }), locked({ id: 'knowledge_documents_document_id', name: 'documentId', dataType: 'Number' }), locked({ id: 'knowledge_documents_knowledge_id', name: 'knowledgeId', dataType: 'Number' }), ], }), ]; function mergeParameter(current: Parameter | undefined, expected: Parameter): Parameter { if (!current) { return { ...expected, children: expected.children?.map((child) => ({ ...child })), }; } const result = { ...current, ...expected, id: current.id || expected.id }; if (expected.children) { const currentChildren = current.children || []; result.children = expected.children.map((child) => mergeParameter( currentChildren.find((item) => item.name === child.name), child, ), ); } return result; } export function ensureKnowledgeOutputDefs(outputDefs?: Parameter[]): Parameter[] { const current = outputDefs || []; return expectedOutputDefs.map((expected) => mergeParameter( current.find((item) => item.name === expected.name), expected, ), ); }