feat: support var show

This commit is contained in:
Joel 2025-03-11 16:09:09 +08:00
parent e624bf381b
commit 6a76e27b05
3 changed files with 50 additions and 27 deletions

View File

@ -3,7 +3,7 @@ import { isArray, uniq } from 'lodash-es'
import type { CodeNodeType } from '../../../code/types'
import type { EndNodeType } from '../../../end/types'
import type { AnswerNodeType } from '../../../answer/types'
import type { LLMNodeType } from '../../../llm/types'
import type { LLMNodeType, StructuredOutput } from '../../../llm/types'
import type { KnowledgeRetrievalNodeType } from '../../../knowledge-retrieval/types'
import type { IfElseNodeType } from '../../../if-else/types'
import type { TemplateTransformNodeType } from '../../../template-transform/types'
@ -20,6 +20,8 @@ import { BlockEnum, InputVarType, VarType } from '@/app/components/workflow/type
import type { StartNodeType } from '@/app/components/workflow/nodes/start/types'
import type { ConversationVariable, EnvironmentVariable, Node, NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
import type { VariableAssignerNodeType } from '@/app/components/workflow/nodes/variable-assigner/types'
import mockStructData from '@/app/components/workflow/nodes/llm/mock-struct-data'
import {
HTTP_REQUEST_OUTPUT_STRUCT,
KNOWLEDGE_RETRIEVAL_OUTPUT_STRUCT,
@ -59,15 +61,18 @@ const findExceptVarInObject = (obj: any, filterVar: (payload: Var, selector: Val
const res: Var = {
variable: obj.variable,
type: isFile ? VarType.file : VarType.object,
children: children.filter((item: Var) => {
children: children.length > 0 ? children.filter((item: Var) => {
const { children } = item
const isStructuredOutput = !!(children as StructuredOutput)?.schema
if (!isStructuredOutput) {
const currSelector = [...value_selector, item.variable]
if (!children)
return filterVar(item, currSelector)
const obj = findExceptVarInObject(item, filterVar, currSelector, false) // File doesn't contains file children
return obj.children && obj.children?.length > 0
}),
return obj.children && (obj.children as Var[])?.length > 0
}
return true // TODO: handle structured output
}) : (children || []),
}
return res
}
@ -138,7 +143,14 @@ const formatItem = (
}
case BlockEnum.LLM: {
res.vars = LLM_OUTPUT_STRUCT
res.vars = [
...LLM_OUTPUT_STRUCT,
{
variable: 'structured_output',
type: VarType.object,
children: mockStructData,
},
]
break
}
@ -404,7 +416,7 @@ const formatItem = (
return false
const obj = findExceptVarInObject(isFile ? { ...v, children } : v, filterVar, selector, isFile)
return obj?.children && obj?.children.length > 0
return obj?.children && ((obj?.children as Var[]).length > 0 || Object.keys((obj?.children as StructuredOutput)?.schema?.properties || {}).length > 0)
}).map((v) => {
const isFile = v.type === VarType.file
@ -428,6 +440,9 @@ const formatItem = (
return findExceptVarInObject(isFile ? { ...v, children } : v, filterVar, selector, isFile)
})
if (res.nodeId === 'llm')
console.log(res)
return res
}
export const toNodeOutputVars = (
@ -527,8 +542,7 @@ export const getVarType = ({
isConstant,
environmentVariables = [],
conversationVariables = [],
}:
{
}: {
valueSelector: ValueSelector
parentNode?: Node | null
isIterationItem?: boolean
@ -1094,12 +1108,14 @@ const varToValueSelectorList = (v: Var, parentValueSelector: ValueSelector, res:
return
res.push([...parentValueSelector, v.variable])
if (v.children && v.children.length > 0) {
v.children.forEach((child) => {
if (v.children) {
if ((v.children as Var[])?.length > 0) {
(v.children as Var[]).forEach((child) => {
varToValueSelectorList(child, [...parentValueSelector, v.variable], res)
})
}
// TODO: handle structured output
}
}
const varsToValueSelectorList = (vars: Var | Var[], parentValueSelector: ValueSelector, res: ValueSelector[]) => {

View File

@ -16,8 +16,10 @@ import Input from '@/app/components/base/input'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
import { checkKeys } from '@/utils/var'
import { FILE_STRUCT } from '@/app/components/workflow/constants'
import type { StructuredOutput } from '../../../llm/types'
import PickerStructurePanel from '@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/picker'
interface ObjectChildrenProps {
type ObjectChildrenProps = {
nodeId: string
title: string
data: Var[]
@ -28,7 +30,7 @@ interface ObjectChildrenProps {
isSupportFileVar?: boolean
}
interface ItemProps {
type ItemProps = {
nodeId: string
title: string
objPath: string[]
@ -51,8 +53,9 @@ const Item: FC<ItemProps> = ({
isSupportFileVar,
isException,
}) => {
const isFile = itemData.type === VarType.file
const isObj = ([VarType.object, VarType.file].includes(itemData.type) && itemData.children && itemData.children.length > 0)
const isStructureOutput = itemData.type === VarType.object && (itemData.children as StructuredOutput)?.schema?.properties
const isFile = itemData.type === VarType.file && !isStructureOutput
const isObj = ([VarType.object, VarType.file].includes(itemData.type) && itemData.children && (itemData.children as Var[]).length > 0)
const isSys = itemData.variable.startsWith('sys.')
const isEnv = itemData.variable.startsWith('env.')
const isChatVar = itemData.variable.startsWith('conversation.')
@ -77,7 +80,7 @@ const Item: FC<ItemProps> = ({
})
const [isChildrenHovering, setIsChildrenHovering] = useState(false)
const isHovering = isItemHovering || isChildrenHovering
const open = isObj && isHovering
const open = (isObj || isStructureOutput) && isHovering
useEffect(() => {
onHovering && onHovering(isHovering)
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -125,7 +128,7 @@ const Item: FC<ItemProps> = ({
)}
</div>
<div className='ml-1 shrink-0 text-xs font-normal text-text-tertiary capitalize'>{itemData.type}</div>
{isObj && (
{(isObj || isStructureOutput) && (
<ChevronRight className={cn('ml-0.5 w-3 h-3 text-text-quaternary', isHovering && 'text-text-tertiary')} />
)}
</div>
@ -133,6 +136,9 @@ const Item: FC<ItemProps> = ({
<PortalToFollowElemContent style={{
zIndex: 100,
}}>
{isStructureOutput && (
<PickerStructurePanel root={{ attrName: itemData.variable }} payload={itemData.children as StructuredOutput} />
)}
{(isObj && !isFile) && (
// eslint-disable-next-line ts/no-use-before-define
<ObjectChildren
@ -226,7 +232,7 @@ const ObjectChildren: FC<ObjectChildrenProps> = ({
)
}
interface Props {
type Props = {
hideSearch?: boolean
searchBoxClassName?: string
vars: NodeOutPutVar[]
@ -322,7 +328,7 @@ const VarReferenceVars: FC<Props> = ({
}
</div>
: <div className='pl-3 leading-[18px] text-xs font-medium text-gray-500 uppercase'>{t('workflow.common.noVar')}</div>}
</ >
</>
)
}
export default React.memo(VarReferenceVars)

View File

@ -14,6 +14,7 @@ import type {
ErrorHandleTypeEnum,
} from '@/app/components/workflow/nodes/_base/components/error-handle/types'
import type { WorkflowRetryConfig } from '@/app/components/workflow/nodes/_base/components/retry/types'
import type { StructuredOutput } from './nodes/llm/types'
export enum BlockEnum {
Start = 'start',
@ -250,7 +251,7 @@ export enum VarType {
export type Var = {
variable: string
type: VarType
children?: Var[] // if type is obj, has the children struct
children?: Var[] | StructuredOutput // if type is obj, has the children struct
isParagraph?: boolean
isSelect?: boolean
options?: string[]