mirror of
https://github.com/langgenius/dify.git
synced 2026-05-10 14:14:17 +08:00
feat: change sub-graph prompt handling to use user role
This commit is contained in:
parent
c5482c2503
commit
b7025ad9d6
@ -48,6 +48,8 @@ const SubGraph: FC<SubGraphProps> = (props) => {
|
||||
desc: '',
|
||||
_connectedSourceHandleIds: ['source'],
|
||||
_connectedTargetHandleIds: [],
|
||||
_subGraphEntry: true,
|
||||
_iconTypeOverride: BlockEnum.Agent,
|
||||
variables: [],
|
||||
},
|
||||
selectable: false,
|
||||
@ -62,9 +64,7 @@ const SubGraph: FC<SubGraphProps> = (props) => {
|
||||
if (!extractorNode)
|
||||
return null
|
||||
|
||||
const updateSystemPrompt = (item: PromptItem) => {
|
||||
if (item.role !== PromptRole.system)
|
||||
return item
|
||||
const applyPromptText = (item: PromptItem) => {
|
||||
if (item.edition_type === EditionType.jinja2) {
|
||||
return {
|
||||
...item,
|
||||
@ -75,36 +75,45 @@ const SubGraph: FC<SubGraphProps> = (props) => {
|
||||
return { ...item, text: promptText }
|
||||
}
|
||||
|
||||
const nextPromptTemplate = Array.isArray(extractorNode.data.prompt_template)
|
||||
? extractorNode.data.prompt_template.map(updateSystemPrompt)
|
||||
: updateSystemPrompt(extractorNode.data.prompt_template as PromptItem)
|
||||
const nextPromptTemplate = (() => {
|
||||
const template = extractorNode.data.prompt_template
|
||||
if (!Array.isArray(template))
|
||||
return applyPromptText(template as PromptItem)
|
||||
|
||||
const hasSystemPrompt = Array.isArray(nextPromptTemplate)
|
||||
&& nextPromptTemplate.some((item: PromptItem) => item.role === PromptRole.system)
|
||||
const defaultSystemPrompt: PromptItem = (() => {
|
||||
const useJinja = Array.isArray(nextPromptTemplate)
|
||||
&& nextPromptTemplate.some((item: PromptItem) => item.edition_type === EditionType.jinja2)
|
||||
if (useJinja) {
|
||||
return {
|
||||
role: PromptRole.system,
|
||||
text: promptText,
|
||||
jinja2_text: promptText,
|
||||
edition_type: EditionType.jinja2,
|
||||
}
|
||||
const userIndex = template.findIndex(item => item.role === PromptRole.user)
|
||||
if (userIndex >= 0) {
|
||||
return template.map((item, index) => {
|
||||
if (index !== userIndex)
|
||||
return item
|
||||
return applyPromptText(item)
|
||||
})
|
||||
}
|
||||
return { role: PromptRole.system, text: promptText }
|
||||
|
||||
const useJinja = template.some((item: PromptItem) => item.edition_type === EditionType.jinja2)
|
||||
const defaultUserPrompt: PromptItem = useJinja
|
||||
? {
|
||||
role: PromptRole.user,
|
||||
text: promptText,
|
||||
jinja2_text: promptText,
|
||||
edition_type: EditionType.jinja2,
|
||||
}
|
||||
: { role: PromptRole.user, text: promptText }
|
||||
const systemIndex = template.findIndex(item => item.role === PromptRole.system)
|
||||
const nextTemplate = [...template]
|
||||
if (systemIndex >= 0)
|
||||
nextTemplate.splice(systemIndex + 1, 0, defaultUserPrompt)
|
||||
else
|
||||
nextTemplate.unshift(defaultUserPrompt)
|
||||
return nextTemplate
|
||||
})()
|
||||
const normalizedPromptTemplate = Array.isArray(nextPromptTemplate)
|
||||
? (hasSystemPrompt ? nextPromptTemplate : [defaultSystemPrompt, ...nextPromptTemplate])
|
||||
: nextPromptTemplate
|
||||
|
||||
return {
|
||||
...extractorNode,
|
||||
hidden: false,
|
||||
position: { x: 450, y: 150 },
|
||||
position: { x: 320, y: 150 },
|
||||
data: {
|
||||
...extractorNode.data,
|
||||
prompt_template: normalizedPromptTemplate,
|
||||
prompt_template: nextPromptTemplate,
|
||||
},
|
||||
}
|
||||
}, [extractorNode, promptText])
|
||||
|
||||
@ -63,6 +63,11 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
const { t } = useTranslation()
|
||||
const nodeRef = useRef<HTMLDivElement>(null)
|
||||
const { nodesReadOnly } = useNodesReadOnly()
|
||||
const { _subGraphEntry, _iconTypeOverride } = data as {
|
||||
_subGraphEntry?: boolean
|
||||
_iconTypeOverride?: BlockEnum
|
||||
}
|
||||
const iconType = _iconTypeOverride ?? data.type
|
||||
|
||||
const { handleNodeIterationChildSizeChange } = useNodeIterationInteractions()
|
||||
const { handleNodeLoopChildSizeChange } = useNodeLoopInteractions()
|
||||
@ -138,6 +143,48 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
return null
|
||||
}, [data._loopIndex, data._runningStatus, t])
|
||||
|
||||
if (_subGraphEntry) {
|
||||
return (
|
||||
<div
|
||||
className="relative"
|
||||
ref={nodeRef}
|
||||
>
|
||||
<NodeSourceHandle
|
||||
id={id}
|
||||
data={data}
|
||||
handleClassName="!top-1/2 !-right-[9px] !-translate-y-1/2 opacity-0 pointer-events-none after:opacity-0"
|
||||
handleId="source"
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
'flex rounded-2xl border p-0.5',
|
||||
showSelectedBorder ? 'border-components-option-card-option-selected-border' : 'border-workflow-block-border',
|
||||
data._waitingRun && 'opacity-70',
|
||||
showRunningBorder && '!border-state-accent-solid',
|
||||
showSuccessBorder && '!border-state-success-solid',
|
||||
showFailedBorder && '!border-state-destructive-solid',
|
||||
showExceptionBorder && '!border-state-warning-solid',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2 rounded-[15px] bg-workflow-block-bg px-3 py-2 shadow-xs">
|
||||
<BlockIcon
|
||||
className="shrink-0"
|
||||
type={iconType}
|
||||
size="md"
|
||||
toolIcon={toolIcon}
|
||||
/>
|
||||
<div
|
||||
title={data.title}
|
||||
className="system-sm-semibold-uppercase text-text-primary"
|
||||
>
|
||||
{data.title}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const nodeContent = (
|
||||
<div
|
||||
className={cn(
|
||||
@ -245,7 +292,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
>
|
||||
<BlockIcon
|
||||
className="mr-2 shrink-0"
|
||||
type={data.type}
|
||||
type={iconType}
|
||||
size="md"
|
||||
toolIcon={toolIcon}
|
||||
/>
|
||||
@ -344,8 +391,9 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
|
||||
const isStartNode = data.type === BlockEnum.Start
|
||||
const isEntryNode = isTriggerNode(data.type as any) || isStartNode
|
||||
const shouldWrapEntryNode = isEntryNode && !(isStartNode && _subGraphEntry)
|
||||
|
||||
return isEntryNode
|
||||
return shouldWrapEntryNode
|
||||
? (
|
||||
<EntryNodeContainer
|
||||
nodeType={isStartNode ? StartNodeTypeEnum.Start : StartNodeTypeEnum.Trigger}
|
||||
|
||||
@ -40,7 +40,7 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
|
||||
}, [toolNodeId, workflowNodes])
|
||||
const toolParamValue = (toolNode?.data as ToolNodeType | undefined)?.tool_parameters?.[paramKey]?.value as string | undefined
|
||||
|
||||
const getSystemPromptText = useCallback((promptTemplate?: PromptItem[] | PromptItem) => {
|
||||
const getUserPromptText = useCallback((promptTemplate?: PromptItem[] | PromptItem) => {
|
||||
if (!promptTemplate)
|
||||
return ''
|
||||
const resolveText = (item?: PromptItem) => {
|
||||
@ -51,6 +51,9 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
|
||||
return item.text || ''
|
||||
}
|
||||
if (Array.isArray(promptTemplate)) {
|
||||
const userPrompt = promptTemplate.find(item => item.role === PromptRole.user)
|
||||
if (userPrompt)
|
||||
return resolveText(userPrompt)
|
||||
const systemPrompt = promptTemplate.find(item => item.role === PromptRole.system)
|
||||
return resolveText(systemPrompt)
|
||||
}
|
||||
@ -62,9 +65,9 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
|
||||
if (!extractorNodeData)
|
||||
return
|
||||
|
||||
const systemPromptText = getSystemPromptText(extractorNodeData.data?.prompt_template)
|
||||
const userPromptText = getUserPromptText(extractorNodeData.data?.prompt_template)
|
||||
const placeholder = `{{@${agentNodeId}.context@}}`
|
||||
const nextValue = `${placeholder}${systemPromptText}`
|
||||
const nextValue = `${placeholder}${userPromptText}`
|
||||
|
||||
const { getNodes, setNodes } = reactflowStore.getState()
|
||||
const nextNodes = getNodes().map((node) => {
|
||||
@ -104,7 +107,7 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
|
||||
// Trigger main graph draft sync to persist changes to backend
|
||||
handleSyncWorkflowDraft(true)
|
||||
setControlPromptEditorRerenderKey(Date.now())
|
||||
}, [agentNodeId, extractorNodeId, getSystemPromptText, handleSyncWorkflowDraft, paramKey, reactflowStore, setControlPromptEditorRerenderKey, toolNodeId])
|
||||
}, [agentNodeId, extractorNodeId, getUserPromptText, handleSyncWorkflowDraft, paramKey, reactflowStore, setControlPromptEditorRerenderKey, toolNodeId])
|
||||
|
||||
return (
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user