diff --git a/web/app/components/base/prompt-editor/index.tsx b/web/app/components/base/prompt-editor/index.tsx index 3e03452651..a98a5bacb7 100644 --- a/web/app/components/base/prompt-editor/index.tsx +++ b/web/app/components/base/prompt-editor/index.tsx @@ -105,7 +105,6 @@ export type PromptEditorProps = { errorMessageBlock?: ErrorMessageBlockType lastRunBlock?: LastRunBlockType isSupportFileVar?: boolean - isMemorySupported?: boolean } const PromptEditor: FC = ({ @@ -131,7 +130,6 @@ const PromptEditor: FC = ({ errorMessageBlock, lastRunBlock, isSupportFileVar, - isMemorySupported, }) => { const { eventEmitter } = useEventEmitterContextContext() const initialConfig = { @@ -202,7 +200,7 @@ const PromptEditor: FC = ({ } ErrorBoundary={LexicalErrorBoundary} /> - {isMemorySupported && workflowVariableBlock?.show && ( + {workflowVariableBlock?.show && workflowVariableBlock?.isMemorySupported && ( v.nodeId === 'memory_block')?.vars || []} @@ -269,7 +267,7 @@ const PromptEditor: FC = ({ { workflowVariableBlock?.show && ( <> - + ) diff --git a/web/app/components/base/prompt-editor/plugins/component-picker-block/hooks.tsx b/web/app/components/base/prompt-editor/plugins/component-picker-block/hooks.tsx index 2032f22ce9..d84271b871 100644 --- a/web/app/components/base/prompt-editor/plugins/component-picker-block/hooks.tsx +++ b/web/app/components/base/prompt-editor/plugins/component-picker-block/hooks.tsx @@ -283,7 +283,19 @@ export const useOptions = ( const workflowVariableOptions = useMemo(() => { if (!workflowVariableBlockType?.show) return [] - const res = workflowVariableBlockType.variables || [] + let res = workflowVariableBlockType.variables || [] + + if (!workflowVariableBlockType.isMemorySupported) { + res = res.map((v) => { + if (v.nodeId === 'conversation') { + return { + ...v, + vars: v.vars.filter(vv => !vv.variable.startsWith('memory_block.')), + } + } + return v + }) + } if(errorMessageBlockType?.show && res.findIndex(v => v.nodeId === 'error_message') === -1) { res.unshift({ nodeId: 'error_message', diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx index e977296bd6..ea805c63ed 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx @@ -2,6 +2,7 @@ import { memo, useCallback, useEffect, + useMemo, useState, } from 'react' import { useTranslation } from 'react-i18next' @@ -34,12 +35,12 @@ type WorkflowVariableBlockComponentProps = { workflowNodesMap: WorkflowNodesMap environmentVariables?: Var[] conversationVariables?: Var[] - memoryVariables?: Var[] ragVariables?: Var[] getVarType?: (payload: { nodeId: string, valueSelector: ValueSelector, }) => Type + isMemorySupported?: boolean } const WorkflowVariableBlockComponent = ({ @@ -49,8 +50,8 @@ const WorkflowVariableBlockComponent = ({ getVarType, environmentVariables, conversationVariables, - memoryVariables, ragVariables, + isMemorySupported, }: WorkflowVariableBlockComponentProps) => { const { t } = useTranslation() const [editor] = useLexicalComposerContext() @@ -72,6 +73,8 @@ const WorkflowVariableBlockComponent = ({ const isMemoryVar = isMemoryVariable(variables) const isException = isExceptionVariable(varName, node?.type) + const memoryVariables = conversationVariables?.filter(v => v.variable.startsWith('memory_block.')) + let variableValid = true if (isEnv) { if (environmentVariables) @@ -84,6 +87,9 @@ const WorkflowVariableBlockComponent = ({ else if (isMemoryVar) { if (memoryVariables) variableValid = memoryVariables.some(v => v.variable === `${variables?.[0] ?? ''}.${variables?.[1] ?? ''}`) + + if (!isMemorySupported) + variableValid = false } else if (isRagVar) { if (ragVariables) @@ -133,11 +139,28 @@ const WorkflowVariableBlockComponent = ({ }) }, [node, reactflow, store]) + const memoriedVariables = useMemo(() => { + if (variables[0] === 'memory_block') { + const currentMemoryVariable = memoryVariables?.find(v => v.variable === variables.join('.')) + + if (currentMemoryVariable && currentMemoryVariable.memoryVariableName) { + return [ + 'memory_block', + currentMemoryVariable.memoryVariableName, + ] + } + + return variables + } + + return variables + }, [memoryVariables, variables]) + const Item = ( { e.stopPropagation() handleVariableJump() @@ -151,7 +174,7 @@ const WorkflowVariableBlockComponent = ({ ) if (!node) - return Item + return
{Item}
return ( } diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx index 479dce9615..b8d5b0b5bd 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx @@ -32,9 +32,19 @@ const WorkflowVariableBlock = memo(({ onInsert, onDelete, getVarType, + variables: originalVariables, + isMemorySupported, }: WorkflowVariableBlockType) => { const [editor] = useLexicalComposerContext() + const ragVariables = originalVariables?.reduce((acc, curr) => { + if (curr.nodeId === 'rag') + acc.push(...curr.vars) + else + acc.push(...curr.vars.filter(v => v.isRagVariable)) + return acc + }, []) + useEffect(() => { editor.update(() => { editor.dispatchCommand(UPDATE_WORKFLOW_NODES_MAP, workflowNodesMap) @@ -50,7 +60,7 @@ const WorkflowVariableBlock = memo(({ INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND, (variables: string[]) => { editor.dispatchCommand(CLEAR_HIDE_MENU_TIMEOUT, undefined) - const workflowVariableBlockNode = $createWorkflowVariableBlockNode(variables, workflowNodesMap, getVarType) + const workflowVariableBlockNode = $createWorkflowVariableBlockNode(variables, workflowNodesMap, getVarType, originalVariables?.find(o => o.nodeId === 'env')?.vars || [], originalVariables?.find(o => o.nodeId === 'conversation')?.vars || [], ragVariables, isMemorySupported) $insertNodes([workflowVariableBlockNode]) if (onInsert) diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx index fa9207ce25..34e3a06dd3 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx @@ -13,8 +13,8 @@ export type SerializedNode = SerializedLexicalNode & { getVarType?: GetVarType environmentVariables?: Var[] conversationVariables?: Var[] - memoryVariables?: Var[] ragVariables?: Var[] + isMemorySupported?: boolean } export class WorkflowVariableBlockNode extends DecoratorNode { @@ -23,8 +23,8 @@ export class WorkflowVariableBlockNode extends DecoratorNode __getVarType?: GetVarType __environmentVariables?: Var[] __conversationVariables?: Var[] - __memoryVariables?: Var[] __ragVariables?: Var[] + __isMemorySupported?: boolean static getType(): string { return 'workflow-variable-block' @@ -45,8 +45,8 @@ export class WorkflowVariableBlockNode extends DecoratorNode key?: NodeKey, environmentVariables?: Var[], conversationVariables?: Var[], - memoryVariables?: Var[], ragVariables?: Var[], + isMemorySupported?: boolean, ) { super(key) @@ -55,8 +55,8 @@ export class WorkflowVariableBlockNode extends DecoratorNode this.__getVarType = getVarType this.__environmentVariables = environmentVariables this.__conversationVariables = conversationVariables - this.__memoryVariables = memoryVariables this.__ragVariables = ragVariables + this.__isMemorySupported = isMemorySupported } createDOM(): HTMLElement { @@ -78,14 +78,14 @@ export class WorkflowVariableBlockNode extends DecoratorNode getVarType={this.__getVarType!} environmentVariables={this.__environmentVariables} conversationVariables={this.__conversationVariables} - memoryVariables={this.__memoryVariables} ragVariables={this.__ragVariables} + isMemorySupported={this.__isMemorySupported} /> ) } static importJSON(serializedNode: SerializedNode): WorkflowVariableBlockNode { - const node = $createWorkflowVariableBlockNode(serializedNode.variables, serializedNode.workflowNodesMap, serializedNode.getVarType, serializedNode.environmentVariables, serializedNode.conversationVariables, serializedNode.ragVariables) + const node = $createWorkflowVariableBlockNode(serializedNode.variables, serializedNode.workflowNodesMap, serializedNode.getVarType, serializedNode.environmentVariables, serializedNode.conversationVariables, serializedNode.ragVariables, serializedNode.isMemorySupported) return node } @@ -99,7 +99,6 @@ export class WorkflowVariableBlockNode extends DecoratorNode getVarType: this.getVarType(), environmentVariables: this.getEnvironmentVariables(), conversationVariables: this.getConversationVariables(), - memoryVariables: this.getMemoryVariables(), ragVariables: this.getRagVariables(), } } @@ -129,22 +128,22 @@ export class WorkflowVariableBlockNode extends DecoratorNode return self.__conversationVariables } - getMemoryVariables(): any { - const self = this.getLatest() - return self.__memoryVariables - } - getRagVariables(): any { const self = this.getLatest() return self.__ragVariables } + getIsMemorySupported() { + const self = this.getLatest() + return self.__isMemorySupported + } + getTextContent(): string { return `{{#${this.getVariables().join('.')}#}}` } } -export function $createWorkflowVariableBlockNode(variables: string[], workflowNodesMap: WorkflowNodesMap, getVarType?: GetVarType, environmentVariables?: Var[], conversationVariables?: Var[], memoryVariables?: Var[], ragVariables?: Var[]): WorkflowVariableBlockNode { - return new WorkflowVariableBlockNode(variables, workflowNodesMap, getVarType, undefined, environmentVariables, conversationVariables, memoryVariables, ragVariables) +export function $createWorkflowVariableBlockNode(variables: string[], workflowNodesMap: WorkflowNodesMap, getVarType?: GetVarType, environmentVariables?: Var[], conversationVariables?: Var[], ragVariables?: Var[], isMemorySupported?: boolean): WorkflowVariableBlockNode { + return new WorkflowVariableBlockNode(variables, workflowNodesMap, getVarType, undefined, environmentVariables, conversationVariables, ragVariables, isMemorySupported) } export function $isWorkflowVariableBlockNode( diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx index d705060fc9..37985d8c2a 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx @@ -19,6 +19,7 @@ const WorkflowVariableBlockReplacementBlock = ({ getVarType, onInsert, variables, + isMemorySupported, }: WorkflowVariableBlockType) => { const [editor] = useLexicalComposerContext() const ragVariables = variables?.reduce((acc, curr) => { @@ -28,7 +29,6 @@ const WorkflowVariableBlockReplacementBlock = ({ acc.push(...curr.vars.filter(v => v.isRagVariable)) return acc }, []) - const memoryVariables = variables?.find(variable => variable.nodeId === 'memory_block')?.vars || [] useEffect(() => { if (!editor.hasNodes([WorkflowVariableBlockNode])) @@ -40,7 +40,7 @@ const WorkflowVariableBlockReplacementBlock = ({ onInsert() const nodePathString = textNode.getTextContent().slice(3, -3) - return $applyNodeReplacement($createWorkflowVariableBlockNode(nodePathString.split('.'), workflowNodesMap, getVarType, variables?.find(o => o.nodeId === 'env')?.vars || [], variables?.find(o => o.nodeId === 'conversation')?.vars || [], memoryVariables, ragVariables)) + return $applyNodeReplacement($createWorkflowVariableBlockNode(nodePathString.split('.'), workflowNodesMap, getVarType, variables?.find(o => o.nodeId === 'env')?.vars || [], variables?.find(o => o.nodeId === 'conversation')?.vars || [], ragVariables, isMemorySupported)) }, [onInsert, workflowNodesMap, getVarType, variables]) const getMatch = useCallback((text: string) => { diff --git a/web/app/components/base/prompt-editor/types.ts b/web/app/components/base/prompt-editor/types.ts index 33de014c0a..5828c7ba18 100644 --- a/web/app/components/base/prompt-editor/types.ts +++ b/web/app/components/base/prompt-editor/types.ts @@ -71,6 +71,7 @@ export type WorkflowVariableBlockType = { getVarType?: GetVarType showManageInputField?: boolean onManageInputField?: () => void + isMemorySupported?: boolean } export type MenuTextMatch = { diff --git a/web/app/components/workflow/nodes/_base/components/prompt/editor.tsx b/web/app/components/workflow/nodes/_base/components/prompt/editor.tsx index b6b1544fc3..dba4bb0940 100644 --- a/web/app/components/workflow/nodes/_base/components/prompt/editor.tsx +++ b/web/app/components/workflow/nodes/_base/components/prompt/editor.tsx @@ -297,13 +297,13 @@ const Editor: FC = ({ }, {} as any), showManageInputField: !!pipelineId, onManageInputField: () => setShowInputFieldPanel?.(true), + isMemorySupported, }} onChange={onChange} onBlur={setBlur} onFocus={setFocus} editable={!readOnly} isSupportFileVar={isSupportFileVar} - isMemorySupported /> {/* to patch Editor not support dynamic change editable status */} {readOnly &&
} diff --git a/web/app/components/workflow/nodes/llm/components/config-prompt-item.tsx b/web/app/components/workflow/nodes/llm/components/config-prompt-item.tsx index 01157ce9ad..7aecf99627 100644 --- a/web/app/components/workflow/nodes/llm/components/config-prompt-item.tsx +++ b/web/app/components/workflow/nodes/llm/components/config-prompt-item.tsx @@ -39,6 +39,7 @@ type Props = { varList: Variable[] handleAddVariable: (payload: any) => void modelConfig?: ModelConfig + isMemorySupported?: boolean } const roleOptions = [ @@ -81,6 +82,7 @@ const ConfigPromptItem: FC = ({ varList, handleAddVariable, modelConfig, + isMemorySupported, }) => { const { t } = useTranslation() const workflowStore = useWorkflowStore() @@ -156,7 +158,7 @@ const ConfigPromptItem: FC = ({ } - isMemorySupported + isMemorySupported={isMemorySupported} /> ) } diff --git a/web/app/components/workflow/nodes/llm/components/config-prompt.tsx b/web/app/components/workflow/nodes/llm/components/config-prompt.tsx index 21a3a81152..921c6b8e12 100644 --- a/web/app/components/workflow/nodes/llm/components/config-prompt.tsx +++ b/web/app/components/workflow/nodes/llm/components/config-prompt.tsx @@ -34,6 +34,7 @@ type Props = { varList?: Variable[] handleAddVariable: (payload: any) => void modelConfig: ModelConfig + isMemorySupported?: boolean } const ConfigPrompt: FC = ({ @@ -49,6 +50,7 @@ const ConfigPrompt: FC = ({ varList = [], handleAddVariable, modelConfig, + isMemorySupported, }) => { const { t } = useTranslation() const workflowStore = useWorkflowStore() @@ -205,6 +207,7 @@ const ConfigPrompt: FC = ({ varList={varList} handleAddVariable={handleAddVariable} modelConfig={modelConfig} + isMemorySupported={isMemorySupported} /> ) @@ -241,6 +244,7 @@ const ConfigPrompt: FC = ({ handleAddVariable={handleAddVariable} onGenerated={handleGenerated} modelConfig={modelConfig} + isMemorySupported={isMemorySupported} /> )} diff --git a/web/app/components/workflow/nodes/llm/panel.tsx b/web/app/components/workflow/nodes/llm/panel.tsx index 44648f12dc..97c38d814c 100644 --- a/web/app/components/workflow/nodes/llm/panel.tsx +++ b/web/app/components/workflow/nodes/llm/panel.tsx @@ -155,6 +155,7 @@ const Panel: FC> = ({ varList={inputs.prompt_config?.jinja2_variables || []} handleAddVariable={handleAddVariable} modelConfig={model} + isMemorySupported={memoryType === MemoryMode.block} /> )} @@ -213,6 +214,7 @@ const Panel: FC> = ({ availableNodes={availableNodesWithParent} isSupportFileVar instanceId={`${id}-chat-workflow-llm-prompt-editor-user`} + isMemorySupported={memoryType === MemoryMode.block} /> {inputs.memory?.query_prompt_template && !inputs.memory.query_prompt_template.includes('{{#sys.query#}}') && ( diff --git a/web/app/components/workflow/panel/chat-variable-panel/components/variable-item.tsx b/web/app/components/workflow/panel/chat-variable-panel/components/variable-item.tsx index 073ec1be98..6e043fe73f 100644 --- a/web/app/components/workflow/panel/chat-variable-panel/components/variable-item.tsx +++ b/web/app/components/workflow/panel/chat-variable-panel/components/variable-item.tsx @@ -1,4 +1,5 @@ -import { memo, useState } from 'react' +import { memo, useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' import { capitalize } from 'lodash-es' import { RiDeleteBinLine, RiEditLine } from '@remixicon/react' import { @@ -27,7 +28,13 @@ const VariableItem = ({ term, currentVarId, }: VariableItemProps) => { + const { t } = useTranslation() const [destructive, setDestructive] = useState(false) + const valueType = useMemo(() => { + if (item.value_type === ChatVarType.Memory) + return 'memory' + return item.value_type + }, [item.value_type]) return (
{item.name}
-
{capitalize(item.value_type)}
+
{capitalize(valueType)}
- {scope && } + {scope === 'app' && } {term && }
@@ -70,6 +77,11 @@ const VariableItem = ({
{item.description}
) } + { + scope === 'app' && ( +
{t('workflow.chatVariable.appScopeText')}
+ ) + } ) } diff --git a/web/app/components/workflow/panel/chat-variable-panel/index.tsx b/web/app/components/workflow/panel/chat-variable-panel/index.tsx index de46538b7a..1dafb04da6 100644 --- a/web/app/components/workflow/panel/chat-variable-panel/index.tsx +++ b/web/app/components/workflow/panel/chat-variable-panel/index.tsx @@ -236,7 +236,7 @@ const ChatVariablePanel = () => { onEdit={handleEdit} onDelete={deleteCheck} term={memoryVariable.term} - scope='conv' + scope='app' currentVarId={currentVar?.id} /> )) diff --git a/web/config/index.ts b/web/config/index.ts index 4e98182c0e..3bbbb20a04 100644 --- a/web/config/index.ts +++ b/web/config/index.ts @@ -311,7 +311,7 @@ Thought: {{agent_scratchpad}} } export const VAR_REGEX - = /\{\{(#[a-zA-Z0-9_-]{1,50}(\.\d+)?(\.[a-zA-Z_]\w{0,29}){1,10}#)\}\}/gi + = /\{\{(#[\w-]{1,50}(?:\.\w+(?:\.[a-zA-Z_]\w{0,29}){0,10}|\.[a-zA-Z_]\w{0,29}(?:\.[a-zA-Z_]\w{0,29}){0,9})#)\}\}/gi export const resetReg = () => (VAR_REGEX.lastIndex = 0) diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index 750c48b84d..c61a44c34f 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -150,6 +150,7 @@ const translation = { docLink: 'Visit our docs to learn more.', button: 'Add Variable', nodeScopeMemory: 'Node Scope Memory', + appScopeText: 'Conversation History', modal: { title: 'Add Conversation Variable', editTitle: 'Edit Conversation Variable', diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index 160eb0a923..68fa9845ae 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -150,6 +150,7 @@ const translation = { docLink: '查看文档了解更多。', button: '添加变量', nodeScopeMemory: '节点范围记忆', + appScopeText: '会话历史', modal: { title: '添加会话变量', editTitle: '编辑会话变量',