From c46856d5ac9598db85f92382ee909d8ad6707bac Mon Sep 17 00:00:00 2001 From: zhsama Date: Tue, 27 Jan 2026 23:54:42 +0800 Subject: [PATCH] feat: Validate LLM node context before running workflow --- .../workflow-panel/last-run/use-last-run.ts | 19 +++++++++++++++++++ web/i18n/en-US/workflow.json | 1 + web/i18n/ja-JP/workflow.json | 1 + web/i18n/zh-Hans/workflow.json | 1 + web/i18n/zh-Hant/workflow.json | 1 + 5 files changed, 23 insertions(+) diff --git a/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/use-last-run.ts b/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/use-last-run.ts index 6baa94c94a..1aa11568e4 100644 --- a/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/use-last-run.ts +++ b/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/use-last-run.ts @@ -1,8 +1,10 @@ import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form' import type { Params as OneStepRunParams } from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run' +import type { LLMNodeType } from '@/app/components/workflow/nodes/llm/types' // import import type { CommonNodeType, ValueSelector } from '@/app/components/workflow/types' import { useCallback, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' import Toast from '@/app/components/base/toast' import { useNodesSyncDraft, @@ -127,6 +129,7 @@ const useLastRun = ({ ...oneStepRunParams }: Params) => { const { conversationVars, systemVars, hasSetInspectVar } = useInspectVarsCrud() + const { t } = useTranslation() const blockType = oneStepRunParams.data.type const isStartNode = blockType === BlockEnum.Start const isIterationNode = blockType === BlockEnum.Iteration @@ -234,12 +237,26 @@ const useLastRun = ({ }, [initShowLastRunTab]) const invalidLastRun = useInvalidLastRun(flowType, flowId, id) + const ensureLLMContextReady = useCallback(() => { + if (blockType !== BlockEnum.LLM) + return true + const llmData = data as unknown as LLMNodeType + const contextSelector = llmData.context?.variable_selector + if (!Array.isArray(contextSelector) || contextSelector.length === 0) { + Toast.notify({ type: 'error', message: t('nodes.llm.contextMissing', { ns: 'workflow' }) }) + return false + } + return true + }, [blockType, data, t]) + const handleRunWithParams = async (data: Record) => { if (blockIfChecklistFailed()) return const { isValid } = checkValid() if (!isValid) return + if (!ensureLLMContextReady()) + return setNodeRunning() setIsRunAfterSingleRun(true) setTabType(TabType.lastRun) @@ -340,6 +357,8 @@ const useLastRun = ({ const { isValid } = checkValid() if (!isValid) return + if (!ensureLLMContextReady()) + return if (blockType === BlockEnum.TriggerWebhook || blockType === BlockEnum.TriggerPlugin || blockType === BlockEnum.TriggerSchedule) setShowVariableInspectPanel(true) if (isCustomRunNode) { diff --git a/web/i18n/en-US/workflow.json b/web/i18n/en-US/workflow.json index 931173a2e7..9e0303d36a 100644 --- a/web/i18n/en-US/workflow.json +++ b/web/i18n/en-US/workflow.json @@ -672,6 +672,7 @@ "nodes.llm.computerUse.tooltip": "Manage the runtime filesystem and tool access for your agent.", "nodes.llm.context": "context", "nodes.llm.contextBlock": "Context Block", + "nodes.llm.contextMissing": "Missing context from previous nodes. Please select a context variable.", "nodes.llm.contextTooltip": "You can import Knowledge as context", "nodes.llm.files": "Files", "nodes.llm.jsonSchema.addChildField": "Add Child Field", diff --git a/web/i18n/ja-JP/workflow.json b/web/i18n/ja-JP/workflow.json index 9bebe798e7..2a7cfee23b 100644 --- a/web/i18n/ja-JP/workflow.json +++ b/web/i18n/ja-JP/workflow.json @@ -648,6 +648,7 @@ "nodes.llm.addMessage": "メッセージ追加", "nodes.llm.context": "コンテキスト", "nodes.llm.contextBlock": "コンテキストブロック", + "nodes.llm.contextMissing": "前のノードのコンテキストがありません。コンテキスト変数を選択してください。", "nodes.llm.contextTooltip": "ナレッジベースをコンテキストとして利用", "nodes.llm.files": "ファイル", "nodes.llm.jsonSchema.addChildField": "サブフィールドを追加", diff --git a/web/i18n/zh-Hans/workflow.json b/web/i18n/zh-Hans/workflow.json index d42dde2937..5e39eb1704 100644 --- a/web/i18n/zh-Hans/workflow.json +++ b/web/i18n/zh-Hans/workflow.json @@ -665,6 +665,7 @@ "nodes.llm.computerUse.tooltip": "管理代理的运行时文件系统与工具访问权限。", "nodes.llm.context": "上下文", "nodes.llm.contextBlock": "上下文块", + "nodes.llm.contextMissing": "缺少前序节点的上下文,请先选择上下文变量。", "nodes.llm.contextTooltip": "您可以导入知识库作为上下文", "nodes.llm.files": "文件", "nodes.llm.jsonSchema.addChildField": "添加子字段", diff --git a/web/i18n/zh-Hant/workflow.json b/web/i18n/zh-Hant/workflow.json index c0640ff8a3..d278dfe457 100644 --- a/web/i18n/zh-Hant/workflow.json +++ b/web/i18n/zh-Hant/workflow.json @@ -648,6 +648,7 @@ "nodes.llm.addMessage": "新增消息", "nodes.llm.context": "上下文", "nodes.llm.contextBlock": "上下文區塊", + "nodes.llm.contextMissing": "缺少前序節點的上下文,請先選擇上下文變數。", "nodes.llm.contextTooltip": "您可以導入知識庫作為上下文", "nodes.llm.files": "文件", "nodes.llm.jsonSchema.addChildField": "新增子欄位",