feat: Add structured output to sub-graph LLM nodes

This commit is contained in:
zhsama
2026-01-14 17:25:06 +08:00
parent c8c048c3a3
commit 4828348532
3 changed files with 42 additions and 6 deletions

View File

@ -3,6 +3,7 @@ import type { LLMNodeType } from '@/app/components/workflow/nodes/llm/types'
import type { StartNodeType } from '@/app/components/workflow/nodes/start/types'
import type { Edge, Node, ValueSelector } from '@/app/components/workflow/types'
import { useMemo } from 'react'
import { Type } from '@/app/components/workflow/nodes/llm/types'
import { BlockEnum, PromptRole } from '@/app/components/workflow/types'
import { AppModeEnum } from '@/types/app'
@ -12,6 +13,7 @@ export const SUBGRAPH_LLM_NODE_ID = 'subgraph-llm'
export const getSubGraphInitialNodes = (
sourceVariable: ValueSelector,
agentName: string,
paramKey: string,
): Node[] => {
const sourceVarName = sourceVariable.length > 1
? sourceVariable.slice(1).join('.')
@ -60,6 +62,19 @@ export const getSubGraphInitialNodes = (
vision: {
enabled: false,
},
structured_output_enabled: true,
structured_output: {
schema: {
type: Type.object,
properties: {
[paramKey]: {
type: Type.string,
},
},
required: [paramKey],
additionalProperties: false,
},
},
},
}
@ -84,11 +99,11 @@ export const getSubGraphInitialEdges = (): Edge[] => {
}
export const useSubGraphInit = (props: SubGraphProps) => {
const { sourceVariable, agentName } = props
const { sourceVariable, agentName, paramKey } = props
const initialNodes = useMemo((): Node[] => {
return getSubGraphInitialNodes(sourceVariable, agentName)
}, [sourceVariable, agentName])
return getSubGraphInitialNodes(sourceVariable, agentName, paramKey)
}, [sourceVariable, agentName, paramKey])
const initialEdges = useMemo((): Edge[] => {
return getSubGraphInitialEdges()

View File

@ -16,6 +16,7 @@ import { useStoreApi } from 'reactflow'
import PromptEditor from '@/app/components/base/prompt-editor'
import { useNodesMetaData, useNodesSyncDraft } from '@/app/components/workflow/hooks'
import { VarKindType as VarKindTypeEnum } from '@/app/components/workflow/nodes/_base/types'
import { Type } from '@/app/components/workflow/nodes/llm/types'
import { useStore } from '@/app/components/workflow/store'
import { BlockEnum } from '@/app/components/workflow/types'
import { generateNewNode, getNodeCustomTypeByNodeDataType } from '@/app/components/workflow/utils'
@ -163,6 +164,19 @@ const MixedVariableTextInput = ({
title: defaultValue.title,
desc: defaultValue.desc || '',
parent_node_id: toolNodeId,
structured_output_enabled: true,
structured_output: {
schema: {
type: Type.object,
properties: {
[paramKey]: {
type: Type.string,
},
},
required: [paramKey],
additionalProperties: false,
},
},
},
position: {
x: 0,
@ -175,7 +189,12 @@ const MixedVariableTextInput = ({
}
}
onChange(newValue, VarKindTypeEnum.mention, DEFAULT_MENTION_CONFIG)
const mentionConfigWithOutputSelector: MentionConfig = {
...DEFAULT_MENTION_CONFIG,
extractor_node_id: toolNodeId && paramKey ? `${toolNodeId}_ext_${paramKey}` : '',
output_selector: paramKey ? ['structured_output', paramKey] : [],
}
onChange(newValue, VarKindTypeEnum.mention, mentionConfigWithOutputSelector)
setControlPromptEditorRerenderKey(Date.now())
}, [handleSyncWorkflowDraft, nodesMetaDataMap, onChange, paramKey, reactFlowStore, setControlPromptEditorRerenderKey, toolNodeId, value])

View File

@ -47,13 +47,15 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
const current = toolParam?.mention_config
const rawSelector = Array.isArray(current?.output_selector) ? current!.output_selector : []
const outputSelector = rawSelector[0] === extractorNodeId ? rawSelector.slice(1) : rawSelector
const defaultOutputSelector = ['structured_output', paramKey]
return {
extractor_node_id: current?.extractor_node_id || extractorNodeId,
output_selector: outputSelector,
output_selector: outputSelector.length > 0 ? outputSelector : defaultOutputSelector,
null_strategy: current?.null_strategy || 'use_default',
default_value: current?.default_value ?? '',
}
}, [extractorNodeId, toolParam?.mention_config])
}, [extractorNodeId, paramKey, toolParam?.mention_config])
const handleMentionConfigChange = useCallback((config: MentionConfig) => {
const { getNodes, setNodes } = reactflowStore.getState()