mirror of https://github.com/langgenius/dify.git
memory var sort
This commit is contained in:
parent
77b7bf9d47
commit
f6623423dd
|
|
@ -31,6 +31,8 @@ export const useWorkflowVariables = () => {
|
|||
filterVar,
|
||||
hideEnv,
|
||||
hideChatVar,
|
||||
conversationVariablesFirst,
|
||||
memoryVarSortFn,
|
||||
}: {
|
||||
parentNode?: Node | null
|
||||
beforeNodes: Node[]
|
||||
|
|
@ -38,6 +40,8 @@ export const useWorkflowVariables = () => {
|
|||
filterVar: (payload: Var, selector: ValueSelector) => boolean
|
||||
hideEnv?: boolean
|
||||
hideChatVar?: boolean
|
||||
conversationVariablesFirst?: boolean
|
||||
memoryVarSortFn?: (a: string, b: string) => number
|
||||
}): NodeOutPutVar[] => {
|
||||
const {
|
||||
conversationVariables,
|
||||
|
|
@ -61,6 +65,8 @@ export const useWorkflowVariables = () => {
|
|||
dataSourceList: dataSourceList ?? [],
|
||||
},
|
||||
schemaTypeDefinitions,
|
||||
conversationVariablesFirst,
|
||||
memoryVarSortFn,
|
||||
})
|
||||
}, [t, workflowStore, schemaTypeDefinitions, buildInTools])
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ import Switch from '@/app/components/base/switch'
|
|||
import { Jinja } from '@/app/components/base/icons/src/vender/workflow'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { useWorkflowVariableType } from '@/app/components/workflow/hooks'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { Memory } from '@/app/components/base/icons/src/vender/line/others'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
|
|
@ -75,10 +77,11 @@ type Props = {
|
|||
titleTooltip?: ReactNode
|
||||
inputClassName?: string
|
||||
editorContainerClassName?: string
|
||||
placeholder?: string
|
||||
placeholder?: string | React.JSX.Element
|
||||
placeholderClassName?: string
|
||||
titleClassName?: string
|
||||
required?: boolean
|
||||
isMemorySupported?: boolean
|
||||
}
|
||||
|
||||
const Editor: FC<Props> = ({
|
||||
|
|
@ -118,6 +121,7 @@ const Editor: FC<Props> = ({
|
|||
titleClassName,
|
||||
editorContainerClassName,
|
||||
required,
|
||||
isMemorySupported,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { eventEmitter } = useEventEmitterContextContext()
|
||||
|
|
@ -233,68 +237,78 @@ const Editor: FC<Props> = ({
|
|||
</div>
|
||||
|
||||
{/* Min: 80 Max: 560. Header: 24 */}
|
||||
<div className={cn('pb-2', isExpand && 'flex grow flex-col')}>
|
||||
<div className={cn('pb-2', isExpand && 'flex grow flex-col', isMemorySupported && isFocus && 'pb-1.5')}>
|
||||
{!(isSupportJinja && editionType === EditionType.jinja2)
|
||||
? (
|
||||
<div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative min-h-[56px] overflow-y-auto px-3', editorContainerClassName)}>
|
||||
<PromptEditor
|
||||
key={controlPromptEditorRerenderKey}
|
||||
placeholder={placeholder}
|
||||
placeholderClassName={placeholderClassName}
|
||||
instanceId={instanceId}
|
||||
compact
|
||||
className={cn('min-h-[56px]', inputClassName)}
|
||||
style={isExpand ? { height: editorExpandHeight - 5 } : {}}
|
||||
value={value}
|
||||
contextBlock={{
|
||||
show: justVar ? false : isShowContext,
|
||||
selectable: !hasSetBlockStatus?.context,
|
||||
canNotAddContext: true,
|
||||
}}
|
||||
historyBlock={{
|
||||
show: justVar ? false : isShowHistory,
|
||||
selectable: !hasSetBlockStatus?.history,
|
||||
history: {
|
||||
user: 'Human',
|
||||
assistant: 'Assistant',
|
||||
},
|
||||
}}
|
||||
queryBlock={{
|
||||
show: false, // use [sys.query] instead of query block
|
||||
selectable: false,
|
||||
}}
|
||||
workflowVariableBlock={{
|
||||
show: true,
|
||||
variables: nodesOutputVars || [],
|
||||
getVarType: getVarType as any,
|
||||
workflowNodesMap: availableNodes.reduce((acc, node) => {
|
||||
acc[node.id] = {
|
||||
title: node.data.title,
|
||||
type: node.data.type,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
position: node.position,
|
||||
}
|
||||
if (node.data.type === BlockEnum.Start) {
|
||||
acc.sys = {
|
||||
title: t('workflow.blocks.start'),
|
||||
type: BlockEnum.Start,
|
||||
<>
|
||||
<div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative min-h-[56px] overflow-y-auto px-3', editorContainerClassName)}>
|
||||
<PromptEditor
|
||||
key={controlPromptEditorRerenderKey}
|
||||
placeholder={placeholder}
|
||||
placeholderClassName={placeholderClassName}
|
||||
instanceId={instanceId}
|
||||
compact
|
||||
className={cn('min-h-[56px]', inputClassName)}
|
||||
style={isExpand ? { height: editorExpandHeight - 5 } : {}}
|
||||
value={value}
|
||||
contextBlock={{
|
||||
show: justVar ? false : isShowContext,
|
||||
selectable: !hasSetBlockStatus?.context,
|
||||
canNotAddContext: true,
|
||||
}}
|
||||
historyBlock={{
|
||||
show: justVar ? false : isShowHistory,
|
||||
selectable: !hasSetBlockStatus?.history,
|
||||
history: {
|
||||
user: 'Human',
|
||||
assistant: 'Assistant',
|
||||
},
|
||||
}}
|
||||
queryBlock={{
|
||||
show: false, // use [sys.query] instead of query block
|
||||
selectable: false,
|
||||
}}
|
||||
workflowVariableBlock={{
|
||||
show: true,
|
||||
variables: nodesOutputVars || [],
|
||||
getVarType,
|
||||
workflowNodesMap: availableNodes.reduce((acc, node) => {
|
||||
acc[node.id] = {
|
||||
title: node.data.title,
|
||||
type: node.data.type,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
position: node.position,
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, {} as any),
|
||||
showManageInputField: !!pipelineId,
|
||||
onManageInputField: () => setShowInputFieldPanel?.(true),
|
||||
}}
|
||||
onChange={onChange}
|
||||
onBlur={setBlur}
|
||||
onFocus={setFocus}
|
||||
editable={!readOnly}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
/>
|
||||
{/* to patch Editor not support dynamic change editable status */}
|
||||
{readOnly && <div className='absolute inset-0 z-10'></div>}
|
||||
</div>
|
||||
if (node.data.type === BlockEnum.Start) {
|
||||
acc.sys = {
|
||||
title: t('workflow.blocks.start'),
|
||||
type: BlockEnum.Start,
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, {} as any),
|
||||
showManageInputField: !!pipelineId,
|
||||
onManageInputField: () => setShowInputFieldPanel?.(true),
|
||||
}}
|
||||
onChange={onChange}
|
||||
onBlur={setBlur}
|
||||
onFocus={setFocus}
|
||||
editable={!readOnly}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
/>
|
||||
{/* to patch Editor not support dynamic change editable status */}
|
||||
{readOnly && <div className='absolute inset-0 z-10'></div>}
|
||||
</div>
|
||||
{isMemorySupported && isFocus && (
|
||||
<div className='pl-1.5'>
|
||||
<Button variant='ghost' size='small' className='text-text-tertiary'>
|
||||
<Memory className='h-3.5 w-3.5' />
|
||||
<span className='ml-1'>{t('workflow.nodes.llm.memory.addButton')}</span>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
: (
|
||||
<div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative min-h-[56px] overflow-y-auto px-3', editorContainerClassName)}>
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ const formatItem = (
|
|||
allPluginInfoList: Record<string, ToolWithProvider[]>,
|
||||
ragVars?: Var[],
|
||||
schemaTypeDefinitions: SchemaTypeDefinition[] = [],
|
||||
memoryVarSortFn?: (a: string, b: string) => number,
|
||||
): NodeOutPutVar => {
|
||||
const { id, data } = item
|
||||
|
||||
|
|
@ -630,6 +631,8 @@ const formatItem = (
|
|||
}
|
||||
|
||||
case 'conversation': {
|
||||
if (memoryVarSortFn)
|
||||
data.chatVarList.sort(memoryVarSortFn)
|
||||
res.vars = data.chatVarList.map((chatVar: ConversationVariable) => {
|
||||
return {
|
||||
variable: `conversation.${chatVar.name}`,
|
||||
|
|
@ -759,6 +762,8 @@ export const toNodeOutputVars = (
|
|||
ragVariables: RAGPipelineVariable[] = [],
|
||||
allPluginInfoList: Record<string, ToolWithProvider[]>,
|
||||
schemaTypeDefinitions?: SchemaTypeDefinition[],
|
||||
conversationVariablesFirst: boolean = false,
|
||||
memoryVarSortFn?: (a: string, b: string) => number,
|
||||
): NodeOutPutVar[] => {
|
||||
// ENV_NODE data format
|
||||
const ENV_NODE = {
|
||||
|
|
@ -801,44 +806,56 @@ export const toNodeOutputVars = (
|
|||
return (b.position?.x || 0) - (a.position?.x || 0)
|
||||
})
|
||||
|
||||
const res = [
|
||||
...sortedNodes.filter(node =>
|
||||
SUPPORT_OUTPUT_VARS_NODE.includes(node?.data?.type),
|
||||
),
|
||||
...(environmentVariables.length > 0 ? [ENV_NODE] : []),
|
||||
...(isChatMode && conversationVariables.length > 0 ? [CHAT_VAR_NODE] : []),
|
||||
...(RAG_PIPELINE_NODE.data.ragVariables.length > 0
|
||||
? [RAG_PIPELINE_NODE]
|
||||
: []),
|
||||
]
|
||||
.map((node) => {
|
||||
let ragVariablesInDataSource: RAGPipelineVariable[] = []
|
||||
if (node.data.type === BlockEnum.DataSource) {
|
||||
ragVariablesInDataSource = ragVariables.filter(
|
||||
ragVariable => ragVariable.belong_to_node_id === node.id,
|
||||
)
|
||||
}
|
||||
return {
|
||||
...formatItem(
|
||||
node,
|
||||
isChatMode,
|
||||
filterVar,
|
||||
allPluginInfoList,
|
||||
ragVariablesInDataSource.map(
|
||||
(ragVariable: RAGPipelineVariable) =>
|
||||
({
|
||||
variable: `rag.${node.id}.${ragVariable.variable}`,
|
||||
type: inputVarTypeToVarType(ragVariable.type as any),
|
||||
description: ragVariable.label,
|
||||
isRagVariable: true,
|
||||
} as Var),
|
||||
),
|
||||
schemaTypeDefinitions,
|
||||
let nodeList = []
|
||||
if (conversationVariablesFirst) {
|
||||
nodeList = [
|
||||
...((isChatMode && conversationVariables.length > 0) ? [CHAT_VAR_NODE] : []),
|
||||
...(environmentVariables.length > 0 ? [ENV_NODE] : []),
|
||||
...sortedNodes.filter(node => SUPPORT_OUTPUT_VARS_NODE.includes(node?.data?.type)),
|
||||
...(RAG_PIPELINE_NODE.data.ragVariables.length > 0
|
||||
? [RAG_PIPELINE_NODE]
|
||||
: []),
|
||||
]
|
||||
}
|
||||
else {
|
||||
nodeList = [
|
||||
...sortedNodes.filter(node => SUPPORT_OUTPUT_VARS_NODE.includes(node?.data?.type)),
|
||||
...(environmentVariables.length > 0 ? [ENV_NODE] : []),
|
||||
...((isChatMode && conversationVariables.length > 0) ? [CHAT_VAR_NODE] : []),
|
||||
...(RAG_PIPELINE_NODE.data.ragVariables.length > 0
|
||||
? [RAG_PIPELINE_NODE]
|
||||
: []),
|
||||
]
|
||||
}
|
||||
|
||||
const res = nodeList.map((node) => {
|
||||
let ragVariablesInDataSource: RAGPipelineVariable[] = []
|
||||
if (node.data.type === BlockEnum.DataSource) {
|
||||
ragVariablesInDataSource = ragVariables.filter(
|
||||
ragVariable => ragVariable.belong_to_node_id === node.id,
|
||||
)
|
||||
}
|
||||
return {
|
||||
...formatItem(
|
||||
node,
|
||||
isChatMode,
|
||||
filterVar,
|
||||
allPluginInfoList,
|
||||
ragVariablesInDataSource.map(
|
||||
(ragVariable: RAGPipelineVariable) =>
|
||||
({
|
||||
variable: `rag.${node.id}.${ragVariable.variable}`,
|
||||
type: inputVarTypeToVarType(ragVariable.type as any),
|
||||
description: ragVariable.label,
|
||||
isRagVariable: true,
|
||||
} as Var),
|
||||
),
|
||||
isStartNode: node.data.type === BlockEnum.Start,
|
||||
}
|
||||
})
|
||||
.filter(item => item.vars.length > 0)
|
||||
schemaTypeDefinitions,
|
||||
memoryVarSortFn,
|
||||
),
|
||||
isStartNode: node.data.type === BlockEnum.Start,
|
||||
}
|
||||
}).filter(item => item.vars.length > 0)
|
||||
return res
|
||||
}
|
||||
|
||||
|
|
@ -1119,6 +1136,8 @@ export const toNodeAvailableVars = ({
|
|||
filterVar,
|
||||
allPluginInfoList,
|
||||
schemaTypeDefinitions,
|
||||
conversationVariablesFirst,
|
||||
memoryVarSortFn,
|
||||
}: {
|
||||
parentNode?: Node | null;
|
||||
t?: any;
|
||||
|
|
@ -1134,6 +1153,8 @@ export const toNodeAvailableVars = ({
|
|||
filterVar: (payload: Var, selector: ValueSelector) => boolean;
|
||||
allPluginInfoList: Record<string, ToolWithProvider[]>;
|
||||
schemaTypeDefinitions?: SchemaTypeDefinition[];
|
||||
conversationVariablesFirst?: boolean
|
||||
memoryVarSortFn?: (a: string, b: string) => number
|
||||
}): NodeOutPutVar[] => {
|
||||
const beforeNodesOutputVars = toNodeOutputVars(
|
||||
beforeNodes,
|
||||
|
|
@ -1144,6 +1165,8 @@ export const toNodeAvailableVars = ({
|
|||
ragVariables,
|
||||
allPluginInfoList,
|
||||
schemaTypeDefinitions,
|
||||
conversationVariablesFirst,
|
||||
memoryVarSortFn,
|
||||
)
|
||||
const isInIteration = parentNode?.data.type === BlockEnum.Iteration
|
||||
if (isInIteration) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ type Params = {
|
|||
hideChatVar?: boolean
|
||||
filterVar: (payload: Var, selector: ValueSelector) => boolean
|
||||
passedInAvailableNodes?: Node[]
|
||||
conversationVariablesFirst?: boolean
|
||||
memoryVarSortFn?: (a: string, b: string) => number
|
||||
}
|
||||
|
||||
// TODO: loop type?
|
||||
|
|
@ -24,6 +26,8 @@ const useAvailableVarList = (nodeId: string, {
|
|||
hideEnv,
|
||||
hideChatVar,
|
||||
passedInAvailableNodes,
|
||||
conversationVariablesFirst,
|
||||
memoryVarSortFn,
|
||||
}: Params = {
|
||||
onlyLeafNodeVar: false,
|
||||
filterVar: () => true,
|
||||
|
|
@ -70,6 +74,8 @@ const useAvailableVarList = (nodeId: string, {
|
|||
filterVar,
|
||||
hideEnv,
|
||||
hideChatVar,
|
||||
conversationVariablesFirst,
|
||||
memoryVarSortFn,
|
||||
}), ...dataSourceRagVars]
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -146,6 +146,17 @@ const ConfigPromptItem: FC<Props> = ({
|
|||
varList={varList}
|
||||
handleAddVariable={handleAddVariable}
|
||||
isSupportFileVar
|
||||
placeholder={
|
||||
<>
|
||||
<div>
|
||||
{t(`${i18nPrefix}.promptEditorPlaceholder1`)}
|
||||
</div>
|
||||
<div>
|
||||
{t(`${i18nPrefix}.promptEditorPlaceholder2`)}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
isMemorySupported
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ type Props = {
|
|||
varList?: Variable[]
|
||||
handleAddVariable: (payload: any) => void
|
||||
modelConfig: ModelConfig
|
||||
memoryVarSortFn?: (a: string, b: string) => number
|
||||
}
|
||||
|
||||
const ConfigPrompt: FC<Props> = ({
|
||||
|
|
@ -49,6 +50,7 @@ const ConfigPrompt: FC<Props> = ({
|
|||
varList = [],
|
||||
handleAddVariable,
|
||||
modelConfig,
|
||||
memoryVarSortFn,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
|
@ -73,6 +75,8 @@ const ConfigPrompt: FC<Props> = ({
|
|||
} = useAvailableVarList(nodeId, {
|
||||
onlyLeafNodeVar: false,
|
||||
filterVar,
|
||||
conversationVariablesFirst: true,
|
||||
memoryVarSortFn,
|
||||
})
|
||||
|
||||
const handleChatModePromptChange = useCallback((index: number) => {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
|
|||
handleStructureOutputChange,
|
||||
filterJinja2InputVar,
|
||||
handleReasoningFormatChange,
|
||||
memoryVarSortFn,
|
||||
} = useConfig(id, data)
|
||||
|
||||
const model = inputs.model
|
||||
|
|
@ -152,6 +153,7 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
|
|||
varList={inputs.prompt_config?.jinja2_variables || []}
|
||||
handleAddVariable={handleAddVariable}
|
||||
modelConfig={model}
|
||||
memoryVarSortFn={memoryVarSortFn}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ const useConfig = (id: string, payload: LLMNodeType) => {
|
|||
const { nodesReadOnly: readOnly } = useNodesReadOnly()
|
||||
const isChatMode = useIsChatMode()
|
||||
|
||||
const defaultConfig = useStore(s => s.nodesDefaultConfigs)[payload.type]
|
||||
const defaultConfig = useStore(s => s.nodesDefaultConfigs)?.[payload.type]
|
||||
const [defaultRolePrefix, setDefaultRolePrefix] = useState<{ user: string; assistant: string }>({ user: '', assistant: '' })
|
||||
const { inputs, setInputs: doSetInputs } = useNodeCrud<LLMNodeType>(id, payload)
|
||||
const inputRef = useRef(inputs)
|
||||
|
|
@ -331,6 +331,17 @@ const useConfig = (id: string, payload: LLMNodeType) => {
|
|||
filterVar: filterMemoryPromptVar,
|
||||
})
|
||||
|
||||
const memoryVarSortFn = useCallback((a: string, b: string) => {
|
||||
const idsInNode = inputs.memory?.block_id || []
|
||||
const aInNode = idsInNode.includes(a)
|
||||
const bInNode = idsInNode.includes(b)
|
||||
|
||||
if (aInNode && !bInNode) return -1
|
||||
if (!aInNode && bInNode) return 1
|
||||
|
||||
return a.localeCompare(b)
|
||||
}, [inputs.memory?.block_id])
|
||||
|
||||
return {
|
||||
readOnly,
|
||||
isChatMode,
|
||||
|
|
@ -364,6 +375,7 @@ const useConfig = (id: string, payload: LLMNodeType) => {
|
|||
handleStructureOutputEnableChange,
|
||||
filterJinja2InputVar,
|
||||
handleReasoningFormatChange,
|
||||
memoryVarSortFn,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -522,6 +522,11 @@ const translation = {
|
|||
saveSchema: 'Please finish editing the current field before saving the schema',
|
||||
},
|
||||
},
|
||||
promptEditorPlaceholder1: 'Click here to edit Prompt',
|
||||
promptEditorPlaceholder2: 'Type \'/\' to insert variable',
|
||||
memory: {
|
||||
addButton: 'Add Memory',
|
||||
},
|
||||
},
|
||||
knowledgeRetrieval: {
|
||||
queryVariable: 'Query Variable',
|
||||
|
|
|
|||
|
|
@ -522,6 +522,11 @@ const translation = {
|
|||
tagged: '保持思考标签',
|
||||
separated: '分开思考标签',
|
||||
},
|
||||
promptEditorPlaceholder1: '点击此处编辑提示词',
|
||||
promptEditorPlaceholder2: '输入 \'/\' 插入变量',
|
||||
memory: {
|
||||
addButton: '添加记忆',
|
||||
},
|
||||
},
|
||||
knowledgeRetrieval: {
|
||||
queryVariable: '查询变量',
|
||||
|
|
|
|||
Loading…
Reference in New Issue