From a3dfd670b0c6e8f72daf9c7de244cced67136b80 Mon Sep 17 00:00:00 2001 From: JzoNg Date: Wed, 27 May 2026 21:03:00 +0800 Subject: [PATCH] fix(web): sys variables not supported in snippet --- .../use-nodes-available-var-list.spec.ts | 57 +++++++++++++++++++ .../hooks/use-nodes-available-var-list.ts | 21 +++++-- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/web/app/components/workflow/hooks/__tests__/use-nodes-available-var-list.spec.ts b/web/app/components/workflow/hooks/__tests__/use-nodes-available-var-list.spec.ts index 1f5654ebda..e38c09fea8 100644 --- a/web/app/components/workflow/hooks/__tests__/use-nodes-available-var-list.spec.ts +++ b/web/app/components/workflow/hooks/__tests__/use-nodes-available-var-list.spec.ts @@ -41,6 +41,31 @@ const outputVars: NodeOutPutVar[] = [{ }] satisfies Var[], }] +const outputVarsWithSystemVars: NodeOutPutVar[] = [ + { + nodeId: 'vars-node', + title: 'Vars', + vars: [ + { + variable: 'answer', + type: VarType.string, + }, + { + variable: 'sys.files', + type: VarType.arrayFile, + }, + ] satisfies Var[], + }, + { + nodeId: 'global', + title: 'SYSTEM', + vars: [{ + variable: 'sys.user_id', + type: VarType.string, + }] satisfies Var[], + }, +] + describe('useNodesAvailableVarList', () => { beforeEach(() => { vi.clearAllMocks() @@ -121,6 +146,38 @@ describe('useNodesAvailableVarList', () => { })) }) + it('filters system variables on snippet canvases', () => { + globalThis.history.pushState({}, '', '/snippets/snippet-1/orchestrate') + mockGetNodeAvailableVars.mockReturnValue(outputVarsWithSystemVars) + + const currentNode = createNode({ id: 'node-a' }) + + const { result } = renderHook(() => useNodesAvailableVarList([currentNode], { + filterVar: () => true, + })) + + expect(result.current['node-a']?.availableVars).toEqual([{ + nodeId: 'vars-node', + title: 'Vars', + vars: [{ + variable: 'answer', + type: VarType.string, + }], + }]) + }) + + it('keeps system variables outside snippet canvases', () => { + mockGetNodeAvailableVars.mockReturnValue(outputVarsWithSystemVars) + + const currentNode = createNode({ id: 'node-a' }) + + const { result } = renderHook(() => useNodesAvailableVarList([currentNode], { + filterVar: () => true, + })) + + expect(result.current['node-a']?.availableVars).toEqual(outputVarsWithSystemVars) + }) + it('returns a callback version that can use leaf nodes or caller-provided nodes', () => { const firstNode = createNode({ id: 'node-a' }) const secondNode = createNode({ id: 'node-b' }) diff --git a/web/app/components/workflow/hooks/use-nodes-available-var-list.ts b/web/app/components/workflow/hooks/use-nodes-available-var-list.ts index 23a77ba849..d3b1d57d0d 100644 --- a/web/app/components/workflow/hooks/use-nodes-available-var-list.ts +++ b/web/app/components/workflow/hooks/use-nodes-available-var-list.ts @@ -9,6 +9,7 @@ import { } from '@/app/components/workflow/hooks' import { appendSnippetInputFieldVars, + isSnippetCanvas, } from '@/app/components/workflow/nodes/_base/hooks/snippet-input-field-vars' import { BlockEnum } from '@/app/components/workflow/types' @@ -35,6 +36,18 @@ const getNodeInfo = (nodeId: string, nodes: Node[]) => { } } +const filterSystemVarsForSnippet = (availableVars: NodeOutPutVar[]) => { + if (!isSnippetCanvas()) + return availableVars + + return availableVars + .map(nodeVar => ({ + ...nodeVar, + vars: nodeVar.vars.filter(variable => !variable.variable.startsWith('sys.')), + })) + .filter(nodeVar => nodeVar.vars.length > 0) +} + // TODO: loop type? const useNodesAvailableVarList = (nodes: Node[], { onlyLeafNodeVar, @@ -69,7 +82,7 @@ const useNodesAvailableVarList = (nodes: Node[], { parentNode: iterationNode, } = getNodeInfo(nodeId, nodes) - const availableVars = [ + const availableVars = filterSystemVarsForSnippet([ ...snippetInputFieldAvailability.availableVars, ...getNodeAvailableVars({ parentNode: iterationNode, @@ -79,7 +92,7 @@ const useNodesAvailableVarList = (nodes: Node[], { hideEnv, hideChatVar, }), - ] + ]) const result = { node, availableVars, @@ -123,7 +136,7 @@ export const useGetNodesAvailableVarList = () => { parentNode: iterationNode, } = getNodeInfo(nodeId, nodes) - const availableVars = [ + const availableVars = filterSystemVarsForSnippet([ ...snippetInputFieldAvailability.availableVars, ...getNodeAvailableVars({ parentNode: iterationNode, @@ -133,7 +146,7 @@ export const useGetNodesAvailableVarList = () => { hideEnv, hideChatVar, }), - ] + ]) const result = { node, availableVars,