mirror of
https://github.com/langgenius/dify.git
synced 2026-06-07 16:23:44 +08:00
feat: improve output node (#35511)
This commit is contained in:
parent
a8f009a965
commit
8cb2cffbf7
@ -81,9 +81,10 @@ describe('useAvailableBlocks', () => {
|
||||
expect(result.current.availableNextBlocks).toEqual([])
|
||||
})
|
||||
|
||||
it('should return empty array for End node', () => {
|
||||
it('should return available nodes for End node', () => {
|
||||
const { result } = renderWorkflowHook(() => useAvailableBlocks(BlockEnum.End), { hooksStoreProps })
|
||||
expect(result.current.availableNextBlocks).toEqual([])
|
||||
expect(result.current.availableNextBlocks.length).toBeGreaterThan(0)
|
||||
expect(result.current.availableNextBlocks).toContain(BlockEnum.Code)
|
||||
})
|
||||
|
||||
it('should return empty array for LoopEnd node', () => {
|
||||
@ -143,10 +144,11 @@ describe('useAvailableBlocks', () => {
|
||||
expect(blocks.availablePrevBlocks).toEqual([])
|
||||
})
|
||||
|
||||
it('should return empty nextBlocks for End/LoopEnd/KnowledgeBase', () => {
|
||||
it('should return empty nextBlocks for LoopEnd/KnowledgeBase and available nodes for End', () => {
|
||||
const { result } = renderWorkflowHook(() => useAvailableBlocks(BlockEnum.LLM), { hooksStoreProps })
|
||||
|
||||
expect(result.current.getAvailableBlocks(BlockEnum.End).availableNextBlocks).toEqual([])
|
||||
expect(result.current.getAvailableBlocks(BlockEnum.End).availableNextBlocks.length).toBeGreaterThan(0)
|
||||
expect(result.current.getAvailableBlocks(BlockEnum.End).availableNextBlocks).toContain(BlockEnum.Code)
|
||||
expect(result.current.getAvailableBlocks(BlockEnum.LoopEnd).availableNextBlocks).toEqual([])
|
||||
expect(result.current.getAvailableBlocks(BlockEnum.KnowledgeBase).availableNextBlocks).toEqual([])
|
||||
})
|
||||
|
||||
@ -372,6 +372,41 @@ describe('useChecklist', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('should detect duplicate output variables across end nodes', () => {
|
||||
const startNode = createNode({ id: 'start', data: { type: BlockEnum.Start, title: 'Start' } })
|
||||
const firstEndNode = createNode({
|
||||
id: 'end-1',
|
||||
data: {
|
||||
type: BlockEnum.End,
|
||||
title: 'Output 1',
|
||||
outputs: [{ variable: 'workflow_id', value_selector: ['sys', 'workflow_id'] }],
|
||||
},
|
||||
})
|
||||
const secondEndNode = createNode({
|
||||
id: 'end-2',
|
||||
data: {
|
||||
type: BlockEnum.End,
|
||||
title: 'Output 2',
|
||||
outputs: [{ variable: 'workflow_id', value_selector: ['sys', 'workflow_id'] }],
|
||||
},
|
||||
})
|
||||
|
||||
const edges = [
|
||||
createEdge({ source: 'start', target: 'end-1' }),
|
||||
createEdge({ source: 'start', target: 'end-2' }),
|
||||
]
|
||||
|
||||
const { result } = renderWorkflowHook(
|
||||
() => useChecklist([startNode, firstEndNode, secondEndNode], edges),
|
||||
)
|
||||
|
||||
const firstWarning = result.current.find((item: ChecklistItem) => item.id === 'end-1')
|
||||
const secondWarning = result.current.find((item: ChecklistItem) => item.id === 'end-2')
|
||||
|
||||
expect(firstWarning?.errorMessages.some(message => message.includes('duplicateOutputVariable'))).toBe(true)
|
||||
expect(secondWarning?.errorMessages.some(message => message.includes('duplicateOutputVariable'))).toBe(true)
|
||||
})
|
||||
|
||||
it('should sync checklist items to the workflow store without render phase update warnings', async () => {
|
||||
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
try {
|
||||
|
||||
@ -30,7 +30,7 @@ export const useAvailableBlocks = (nodeType?: BlockEnum, inContainer?: boolean)
|
||||
return availableNodesType
|
||||
}, [availableNodesType, nodeType])
|
||||
const availableNextBlocks = useMemo(() => {
|
||||
if (!nodeType || nodeType === BlockEnum.End || nodeType === BlockEnum.LoopEnd || nodeType === BlockEnum.KnowledgeBase)
|
||||
if (!nodeType || nodeType === BlockEnum.LoopEnd || nodeType === BlockEnum.KnowledgeBase)
|
||||
return []
|
||||
|
||||
return availableNodesType
|
||||
@ -42,7 +42,7 @@ export const useAvailableBlocks = (nodeType?: BlockEnum, inContainer?: boolean)
|
||||
availablePrevBlocks = []
|
||||
|
||||
let availableNextBlocks = availableNodesType
|
||||
if (!nodeType || nodeType === BlockEnum.End || nodeType === BlockEnum.LoopEnd || nodeType === BlockEnum.KnowledgeBase)
|
||||
if (!nodeType || nodeType === BlockEnum.LoopEnd || nodeType === BlockEnum.KnowledgeBase)
|
||||
availableNextBlocks = []
|
||||
|
||||
return {
|
||||
|
||||
@ -91,6 +91,43 @@ const START_NODE_TYPES: BlockEnum[] = [
|
||||
BlockEnum.TriggerPlugin,
|
||||
]
|
||||
|
||||
const getDuplicateEndOutputMessages = (
|
||||
nodes: Node[],
|
||||
t: ReturnType<typeof useTranslation>['t'],
|
||||
) => {
|
||||
const variableOccurrences = new Map<string, string[]>()
|
||||
|
||||
nodes.forEach((node) => {
|
||||
if (node.type !== CUSTOM_NODE || node.data.type !== BlockEnum.End)
|
||||
return
|
||||
|
||||
const outputs = ((node.data as { outputs?: Array<{ variable?: string }> }).outputs) || []
|
||||
outputs.forEach((output) => {
|
||||
const variable = output.variable?.trim()
|
||||
if (!variable)
|
||||
return
|
||||
|
||||
const occurrences = variableOccurrences.get(variable) || []
|
||||
occurrences.push(node.id)
|
||||
variableOccurrences.set(variable, occurrences)
|
||||
})
|
||||
})
|
||||
|
||||
const nodeMessages = new Map<string, string[]>()
|
||||
variableOccurrences.forEach((nodeIds, variable) => {
|
||||
if (nodeIds.length <= 1)
|
||||
return
|
||||
|
||||
Array.from(new Set(nodeIds)).forEach((nodeId) => {
|
||||
const messages = nodeMessages.get(nodeId) || []
|
||||
messages.push(t('errorMsg.duplicateOutputVariable', { ns: 'workflow', variable }))
|
||||
nodeMessages.set(nodeId, messages)
|
||||
})
|
||||
})
|
||||
|
||||
return nodeMessages
|
||||
}
|
||||
|
||||
export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
||||
const { t } = useTranslation()
|
||||
const language = useGetLanguage()
|
||||
@ -179,6 +216,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
||||
const needWarningNodes = useMemo<ChecklistItem[]>(() => {
|
||||
const list: ChecklistItem[] = []
|
||||
const filteredNodes = nodes.filter(node => node.type === CUSTOM_NODE)
|
||||
const duplicateEndOutputMessages = getDuplicateEndOutputMessages(filteredNodes, t)
|
||||
const { validNodes } = getValidTreeNodes(filteredNodes, edges)
|
||||
const installedPluginIds = new Set(modelProviders.map(p => extractPluginId(p.provider)))
|
||||
|
||||
@ -253,6 +291,8 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
||||
}
|
||||
if (hasInvalidVar)
|
||||
errorMessages.push(t('errorMsg.invalidVariable', { ns: 'workflow' }))
|
||||
|
||||
errorMessages.push(...(duplicateEndOutputMessages.get(node!.id) || []))
|
||||
}
|
||||
|
||||
const isStartNodeMeta = nodesExtraData?.[node!.data.type as BlockEnum]?.metaData.isStart ?? false
|
||||
@ -386,6 +426,7 @@ export const useChecklistBeforePublish = () => {
|
||||
} = workflowStore.getState()
|
||||
const nodes = getNodes()
|
||||
const filteredNodes = nodes.filter(node => node.type === CUSTOM_NODE)
|
||||
const duplicateEndOutputMessages = getDuplicateEndOutputMessages(filteredNodes, t)
|
||||
const { validNodes, maxDepth } = getValidTreeNodes(filteredNodes, edges)
|
||||
|
||||
if (maxDepth > MAX_TREE_DEPTH) {
|
||||
@ -500,6 +541,12 @@ export const useChecklistBeforePublish = () => {
|
||||
return false
|
||||
}
|
||||
|
||||
const duplicateOutputMessages = duplicateEndOutputMessages.get(node!.id) || []
|
||||
if (duplicateOutputMessages.length > 0) {
|
||||
toast.error(`[${node!.data.title}] ${duplicateOutputMessages[0]}`)
|
||||
return false
|
||||
}
|
||||
|
||||
const availableVars = map[node!.id]!.availableVars
|
||||
|
||||
for (const variable of usedVars) {
|
||||
|
||||
@ -27,6 +27,9 @@ describe('useWorkflowFinished', () => {
|
||||
data: { status: 'succeeded', outputs: { a: 'hello', b: 'world' } },
|
||||
} as WorkflowFinishedResponse)
|
||||
|
||||
expect(store.getState().workflowRunningData!.resultTabActive).toBeFalsy()
|
||||
const state = store.getState().workflowRunningData!
|
||||
expect(state.result.status).toBe('succeeded')
|
||||
expect(state.resultTabActive).toBe(false)
|
||||
expect(state.resultText).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
@ -16,4 +16,52 @@ describe('useWorkflowTextChunk', () => {
|
||||
expect(state.resultText).toBe('Hello World')
|
||||
expect(state.resultTabActive).toBe(true)
|
||||
})
|
||||
|
||||
it('inserts a line break when text chunks switch to a different output selector', () => {
|
||||
const { result, store } = renderWorkflowHook(() => useWorkflowTextChunk(), {
|
||||
initialStoreState: {
|
||||
workflowRunningData: baseRunningData({ resultText: 'Hello', resultTextSelectorKey: 'end.answer' }),
|
||||
},
|
||||
})
|
||||
|
||||
result.current.handleWorkflowTextChunk({
|
||||
data: { text: '42', from_variable_selector: ['end', 'count'] },
|
||||
} as TextChunkResponse)
|
||||
|
||||
const state = store.getState().workflowRunningData!
|
||||
expect(state.resultText).toBe('Hello\n42')
|
||||
expect(state.resultTextSelectorKey).toBe('end.count')
|
||||
})
|
||||
|
||||
it('does not add an extra line break when the incoming chunk already starts with one', () => {
|
||||
const { result, store } = renderWorkflowHook(() => useWorkflowTextChunk(), {
|
||||
initialStoreState: {
|
||||
workflowRunningData: baseRunningData({ resultText: 'Hello', resultTextSelectorKey: 'end.answer' }),
|
||||
},
|
||||
})
|
||||
|
||||
result.current.handleWorkflowTextChunk({
|
||||
data: { text: '\n42', from_variable_selector: ['end', 'count'] },
|
||||
} as TextChunkResponse)
|
||||
|
||||
const state = store.getState().workflowRunningData!
|
||||
expect(state.resultText).toBe('Hello\n42')
|
||||
expect(state.resultTextSelectorKey).toBe('end.count')
|
||||
})
|
||||
|
||||
it('does not insert a line break when text chunks stay on the same output selector', () => {
|
||||
const { result, store } = renderWorkflowHook(() => useWorkflowTextChunk(), {
|
||||
initialStoreState: {
|
||||
workflowRunningData: baseRunningData({ resultText: 'Hello', resultTextSelectorKey: 'end.answer' }),
|
||||
},
|
||||
})
|
||||
|
||||
result.current.handleWorkflowTextChunk({
|
||||
data: { text: ' world', from_variable_selector: ['end', 'answer'] },
|
||||
} as TextChunkResponse)
|
||||
|
||||
const state = store.getState().workflowRunningData!
|
||||
expect(state.resultText).toBe('Hello world')
|
||||
expect(state.resultTextSelectorKey).toBe('end.answer')
|
||||
})
|
||||
})
|
||||
|
||||
@ -40,6 +40,7 @@ export const useWorkflowStarted = () => {
|
||||
status: WorkflowRunningStatus.Running,
|
||||
}
|
||||
draft.resultText = ''
|
||||
draft.resultTextSelectorKey = undefined
|
||||
}))
|
||||
const nodes = getNodes()
|
||||
const newNodes = produce(nodes, (draft) => {
|
||||
|
||||
@ -7,15 +7,26 @@ export const useWorkflowTextChunk = () => {
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const handleWorkflowTextChunk = useCallback((params: TextChunkResponse) => {
|
||||
const { data: { text } } = params
|
||||
const { data: { text, from_variable_selector } } = params
|
||||
const {
|
||||
workflowRunningData,
|
||||
setWorkflowRunningData,
|
||||
} = workflowStore.getState()
|
||||
const nextSelectorKey = from_variable_selector?.join('.')
|
||||
|
||||
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
|
||||
draft.resultTabActive = true
|
||||
const shouldInsertLineBreak = nextSelectorKey
|
||||
&& draft.resultText
|
||||
&& draft.resultTextSelectorKey
|
||||
&& draft.resultTextSelectorKey !== nextSelectorKey
|
||||
&& !draft.resultText.endsWith('\n')
|
||||
&& !text.startsWith('\n')
|
||||
if (shouldInsertLineBreak)
|
||||
draft.resultText += '\n'
|
||||
draft.resultText += text
|
||||
if (nextSelectorKey)
|
||||
draft.resultTextSelectorKey = nextSelectorKey
|
||||
}))
|
||||
}, [workflowStore])
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ export const useWorkflowTextReplace = () => {
|
||||
} = workflowStore.getState()
|
||||
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
|
||||
draft.resultText = text
|
||||
draft.resultTextSelectorKey = undefined
|
||||
}))
|
||||
}, [workflowStore])
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import type { FileUploadConfigResponse } from '@/models/common'
|
||||
type PreviewRunningData = WorkflowRunningData & {
|
||||
resultTabActive?: boolean
|
||||
resultText?: string
|
||||
resultTextSelectorKey?: string
|
||||
// human input form schema or data cached when node is in 'Paused' status
|
||||
extraContentAndFormData?: Record<string, unknown>
|
||||
}
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "الرجاء إضافة عقدة البداية أولاً قبل {{operation}}",
|
||||
"errorMsg.authRequired": "الترخيص مطلوب",
|
||||
"errorMsg.configureModel": "قم بتكوين نموذج",
|
||||
"errorMsg.duplicateOutputVariable": "متغير عقدة الإخراج \"{{variable}}\" مكرر. يجب أن تكون أسماء متغيرات عقدة الإخراج فريدة.",
|
||||
"errorMsg.fieldRequired": "{{field}} مطلوب",
|
||||
"errorMsg.fields.code": "الكود",
|
||||
"errorMsg.fields.model": "النموذج",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Bitte füge zuerst einen Startknoten hinzu, bevor du {{operation}}.",
|
||||
"errorMsg.authRequired": "Autorisierung ist erforderlich",
|
||||
"errorMsg.configureModel": "Modell konfigurieren",
|
||||
"errorMsg.duplicateOutputVariable": "Doppelte Variable des Output-Knotens \"{{variable}}\". Variablennamen von Output-Knoten müssen eindeutig sein.",
|
||||
"errorMsg.fieldRequired": "{{field}} ist erforderlich",
|
||||
"errorMsg.fields.code": "Code",
|
||||
"errorMsg.fields.model": "Modell",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Please add a start node first before {{operation}}",
|
||||
"errorMsg.authRequired": "Authorization is required",
|
||||
"errorMsg.configureModel": "Configure a model",
|
||||
"errorMsg.duplicateOutputVariable": "Duplicate Output node variable \"{{variable}}\". Output node variable names must be unique.",
|
||||
"errorMsg.fieldRequired": "{{field}} is required",
|
||||
"errorMsg.fields.code": "Code",
|
||||
"errorMsg.fields.model": "Model",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Por favor, agregue primero un nodo de inicio antes de {{operation}}",
|
||||
"errorMsg.authRequired": "Se requiere autorización",
|
||||
"errorMsg.configureModel": "Configura un modelo",
|
||||
"errorMsg.duplicateOutputVariable": "Variable duplicada del nodo de salida \"{{variable}}\". Los nombres de las variables del nodo de salida deben ser únicos.",
|
||||
"errorMsg.fieldRequired": "Se requiere {{field}}",
|
||||
"errorMsg.fields.code": "Código",
|
||||
"errorMsg.fields.model": "Modelo",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "لطفاً قبل از {{operation}} ابتدا یک گره شروع اضافه کنید",
|
||||
"errorMsg.authRequired": "احراز هویت الزامی است",
|
||||
"errorMsg.configureModel": "یک مدل پیکربندی کنید",
|
||||
"errorMsg.duplicateOutputVariable": "متغیر گره خروجی «{{variable}}» تکراری است. نام متغیرهای گره خروجی باید یکتا باشند.",
|
||||
"errorMsg.fieldRequired": "{{field}} الزامی است",
|
||||
"errorMsg.fields.code": "کد",
|
||||
"errorMsg.fields.model": "مدل",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Veuillez d'abord ajouter un nœud de départ avant {{operation}}",
|
||||
"errorMsg.authRequired": "Autorisation requise",
|
||||
"errorMsg.configureModel": "Configurez un modèle",
|
||||
"errorMsg.duplicateOutputVariable": "Variable du nœud de sortie en double \"{{variable}}\". Les noms des variables du nœud de sortie doivent être uniques.",
|
||||
"errorMsg.fieldRequired": "{{field}} est requis",
|
||||
"errorMsg.fields.code": "Code",
|
||||
"errorMsg.fields.model": "Modèle",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "कृपया {{operation}} से पहले एक प्रारंभ नोड जोड़ें",
|
||||
"errorMsg.authRequired": "प्राधिकरण आवश्यक है",
|
||||
"errorMsg.configureModel": "एक मॉडल कॉन्फ़िगर करें",
|
||||
"errorMsg.duplicateOutputVariable": "आउटपुट नोड वेरिएबल \"{{variable}}\" डुप्लिकेट है। आउटपुट नोड वेरिएबल के नाम यूनिक होने चाहिए।",
|
||||
"errorMsg.fieldRequired": "{{field}} आवश्यक है",
|
||||
"errorMsg.fields.code": "कोड",
|
||||
"errorMsg.fields.model": "मॉडल",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Silakan tambahkan node awal terlebih dahulu sebelum {{operation}}",
|
||||
"errorMsg.authRequired": "Otorisasi diperlukan",
|
||||
"errorMsg.configureModel": "Konfigurasikan model",
|
||||
"errorMsg.duplicateOutputVariable": "Variabel node output duplikat \"{{variable}}\". Nama variabel node output harus unik.",
|
||||
"errorMsg.fieldRequired": "{{field}} wajib diisi",
|
||||
"errorMsg.fields.code": "Kode",
|
||||
"errorMsg.fields.model": "Model",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Per favore aggiungi prima un nodo iniziale prima di {{operation}}",
|
||||
"errorMsg.authRequired": "È richiesta l'autorizzazione",
|
||||
"errorMsg.configureModel": "Configura un modello",
|
||||
"errorMsg.duplicateOutputVariable": "Variabile del nodo di output duplicata \"{{variable}}\". I nomi delle variabili del nodo di output devono essere univoci.",
|
||||
"errorMsg.fieldRequired": "{{field}} è richiesto",
|
||||
"errorMsg.fields.code": "Codice",
|
||||
"errorMsg.fields.model": "Modello",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "{{operation}}前に開始ノードを追加してください",
|
||||
"errorMsg.authRequired": "認証が必要です",
|
||||
"errorMsg.configureModel": "モデルを設定してください",
|
||||
"errorMsg.duplicateOutputVariable": "出力ノード変数「{{variable}}」が重複しています。出力ノード変数名は一意である必要があります。",
|
||||
"errorMsg.fieldRequired": "{{field}} は必須です",
|
||||
"errorMsg.fields.code": "コード",
|
||||
"errorMsg.fields.model": "モデル",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "{{operation}} 전에 먼저 시작 노드를 추가해 주세요",
|
||||
"errorMsg.authRequired": "인증이 필요합니다",
|
||||
"errorMsg.configureModel": "모델을 구성하세요",
|
||||
"errorMsg.duplicateOutputVariable": "출력 노드 변수 \"{{variable}}\"가 중복되었습니다. 출력 노드 변수 이름은 고유해야 합니다.",
|
||||
"errorMsg.fieldRequired": "{{field}}가 필요합니다",
|
||||
"errorMsg.fields.code": "코드",
|
||||
"errorMsg.fields.model": "모델",
|
||||
|
||||
@ -130,7 +130,7 @@
|
||||
"comments.filter.all": "Alles",
|
||||
"comments.filter.onlyYourThreads": "Alleen jouw threads",
|
||||
"comments.filter.showResolved": "Opgeloste tonen",
|
||||
"comments.loading": "Laden\u2026",
|
||||
"comments.loading": "Laden…",
|
||||
"comments.noComments": "Nog geen reacties",
|
||||
"comments.panelTitle": "Reactie",
|
||||
"comments.placeholder.add": "Voeg een reactie toe",
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Please add a start node first before {{operation}}",
|
||||
"errorMsg.authRequired": "Authorization is required",
|
||||
"errorMsg.configureModel": "Configureer een model",
|
||||
"errorMsg.duplicateOutputVariable": "Dubbele variabele van de outputnode \"{{variable}}\". Namen van outputnode-variabelen moeten uniek zijn.",
|
||||
"errorMsg.fieldRequired": "{{field}} is required",
|
||||
"errorMsg.fields.code": "Code",
|
||||
"errorMsg.fields.model": "Model",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Najpierw dodaj węzeł początkowy przed {{operation}}",
|
||||
"errorMsg.authRequired": "Wymagana autoryzacja",
|
||||
"errorMsg.configureModel": "Skonfiguruj model",
|
||||
"errorMsg.duplicateOutputVariable": "Zduplikowana zmienna węzła wyjściowego \"{{variable}}\". Nazwy zmiennych węzła wyjściowego muszą być unikalne.",
|
||||
"errorMsg.fieldRequired": "{{field}} jest wymagane",
|
||||
"errorMsg.fields.code": "Kod",
|
||||
"errorMsg.fields.model": "Model",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Por favor, adicione um nó inicial antes de {{operation}}",
|
||||
"errorMsg.authRequired": "Autorização é necessária",
|
||||
"errorMsg.configureModel": "Configure um modelo",
|
||||
"errorMsg.duplicateOutputVariable": "Variável duplicada do nó de saída \"{{variable}}\". Os nomes das variáveis do nó de saída devem ser únicos.",
|
||||
"errorMsg.fieldRequired": "{{field}} é obrigatório",
|
||||
"errorMsg.fields.code": "Código",
|
||||
"errorMsg.fields.model": "Modelo",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Vă rugăm să adăugați mai întâi un nod de pornire înainte de {{operation}}",
|
||||
"errorMsg.authRequired": "Autorizarea este necesară",
|
||||
"errorMsg.configureModel": "Configurați un model",
|
||||
"errorMsg.duplicateOutputVariable": "Variabilă duplicată a nodului de ieșire „{{variable}}”. Numele variabilelor nodului de ieșire trebuie să fie unice.",
|
||||
"errorMsg.fieldRequired": "{{field}} este obligatoriu",
|
||||
"errorMsg.fields.code": "Cod",
|
||||
"errorMsg.fields.model": "Model",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Пожалуйста, сначала добавьте начальный узел перед {{operation}}",
|
||||
"errorMsg.authRequired": "Требуется авторизация",
|
||||
"errorMsg.configureModel": "Настройте модель",
|
||||
"errorMsg.duplicateOutputVariable": "Повторяющаяся переменная узла вывода \"{{variable}}\". Имена переменных узла вывода должны быть уникальными.",
|
||||
"errorMsg.fieldRequired": "{{field}} обязательно для заполнения",
|
||||
"errorMsg.fields.code": "Код",
|
||||
"errorMsg.fields.model": "Модель",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Prosimo, najprej dodajte začetni vozel pred {{operation}}",
|
||||
"errorMsg.authRequired": "Zahtevana je avtorizacija",
|
||||
"errorMsg.configureModel": "Konfiguriraj model",
|
||||
"errorMsg.duplicateOutputVariable": "Podvojena spremenljivka izhodnega vozlišča \"{{variable}}\". Imena spremenljivk izhodnega vozlišča morajo biti enolična.",
|
||||
"errorMsg.fieldRequired": "{{field}} je obvezno",
|
||||
"errorMsg.fields.code": "Koda",
|
||||
"errorMsg.fields.model": "Model",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "โปรดเพิ่มโหนดเริ่มต้นก่อน {{operation}}",
|
||||
"errorMsg.authRequired": "ต้องได้รับอนุญาต",
|
||||
"errorMsg.configureModel": "กำหนดค่าโมเดล",
|
||||
"errorMsg.duplicateOutputVariable": "ตัวแปรของโหนดเอาต์พุต \"{{variable}}\" ซ้ำกัน ชื่อตัวแปรของโหนดเอาต์พุตต้องไม่ซ้ำกัน",
|
||||
"errorMsg.fieldRequired": "{{field}} เป็นสิ่งจําเป็น",
|
||||
"errorMsg.fields.code": "รหัส",
|
||||
"errorMsg.fields.model": "แบบ",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Lütfen {{operation}} işleminden önce önce bir başlangıç düğümü ekleyin",
|
||||
"errorMsg.authRequired": "Yetkilendirme gereklidir",
|
||||
"errorMsg.configureModel": "Bir model yapılandırın",
|
||||
"errorMsg.duplicateOutputVariable": "Yinelenen çıktı düğümü değişkeni \"{{variable}}\". Çıktı düğümü değişken adları benzersiz olmalıdır.",
|
||||
"errorMsg.fieldRequired": "{{field}} gereklidir",
|
||||
"errorMsg.fields.code": "Kod",
|
||||
"errorMsg.fields.model": "Model",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Будь ласка, спершу додайте стартовий вузол перед {{operation}}",
|
||||
"errorMsg.authRequired": "Потрібна авторизація",
|
||||
"errorMsg.configureModel": "Налаштуйте модель",
|
||||
"errorMsg.duplicateOutputVariable": "Дубльована змінна вузла виводу \"{{variable}}\". Назви змінних вузла виводу мають бути унікальними.",
|
||||
"errorMsg.fieldRequired": "{{field}} є обов'язковим",
|
||||
"errorMsg.fields.code": "Код",
|
||||
"errorMsg.fields.model": "Модель",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "Vui lòng thêm một nút bắt đầu trước {{operation}}",
|
||||
"errorMsg.authRequired": "Yêu cầu xác thực",
|
||||
"errorMsg.configureModel": "Cấu hình mô hình",
|
||||
"errorMsg.duplicateOutputVariable": "Biến của nút đầu ra \"{{variable}}\" bị trùng lặp. Tên biến của nút đầu ra phải là duy nhất.",
|
||||
"errorMsg.fieldRequired": "{{field}} là bắt buộc",
|
||||
"errorMsg.fields.code": "Mã",
|
||||
"errorMsg.fields.model": "Mô hình",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "请先添加开始节点,然后再{{operation}}",
|
||||
"errorMsg.authRequired": "请先授权",
|
||||
"errorMsg.configureModel": "请配置模型",
|
||||
"errorMsg.duplicateOutputVariable": "输出节点变量“{{variable}}”重复。输出节点变量名必须唯一。",
|
||||
"errorMsg.fieldRequired": "{{field}} 不能为空",
|
||||
"errorMsg.fields.code": "代码",
|
||||
"errorMsg.fields.model": "模型",
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"error.startNodeRequired": "請先新增一個起始節點,再執行 {{operation}}",
|
||||
"errorMsg.authRequired": "請先授權",
|
||||
"errorMsg.configureModel": "請配置模型",
|
||||
"errorMsg.duplicateOutputVariable": "輸出節點變數「{{variable}}」重複。輸出節點變數名稱必須唯一。",
|
||||
"errorMsg.fieldRequired": "{{field}} 不能為空",
|
||||
"errorMsg.fields.code": "程式碼",
|
||||
"errorMsg.fields.model": "模型",
|
||||
|
||||
@ -305,6 +305,7 @@ export type TextChunkResponse = {
|
||||
event: string
|
||||
data: {
|
||||
text: string
|
||||
from_variable_selector?: string[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user