diff --git a/web/app/components/base/prompt-editor/index.tsx b/web/app/components/base/prompt-editor/index.tsx index 73262cb6a6..7a6a844702 100644 --- a/web/app/components/base/prompt-editor/index.tsx +++ b/web/app/components/base/prompt-editor/index.tsx @@ -80,6 +80,9 @@ import { UPDATE_HISTORY_EVENT_EMITTER, } from './constants' import { useEventEmitterContextContext } from '@/context/event-emitter' +import type { + ConversationVariable, +} from '@/app/components/workflow/types' import cn from '@/utils/classnames' export type PromptEditorProps = { @@ -106,6 +109,8 @@ export type PromptEditorProps = { lastRunBlock?: LastRunBlockType isSupportFileVar?: boolean isMemorySupported?: boolean + memoryVarInNode?: ConversationVariable[] + memoryVarInApp?: ConversationVariable[] } const PromptEditor: FC = ({ @@ -132,6 +137,8 @@ const PromptEditor: FC = ({ lastRunBlock, isSupportFileVar, isMemorySupported, + memoryVarInNode = [], + memoryVarInApp = [], }) => { const { eventEmitter } = useEventEmitterContextContext() const initialConfig = { @@ -203,7 +210,11 @@ const PromptEditor: FC = ({ ErrorBoundary={LexicalErrorBoundary} /> {isMemorySupported && ( - + )} { + editor.dispatchCommand(INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND, variable) + closePortal() + }, [editor, closePortal]) + useEffect(() => { return editor.registerUpdateListener(({ editorState }) => { editorState.read(() => { @@ -155,22 +172,68 @@ export default function MemoryPopupPlugin({ return null return createPortal( -
{ - portalRef.current = node - refs.setFloating(node) - }} - className={cn( - useContainer ? '' : 'z-[999999]', - 'absolute rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm', - className, - )} - style={{ - ...floatingStyles, - visibility: isPositioned ? 'visible' : 'hidden', - }} - > - Memory Popup +
+
{ + portalRef.current = node + refs.setFloating(node) + }} + className={cn( + useContainer ? '' : 'z-[999999]', + 'absolute rounded-xl shadow-lg backdrop-blur-sm', + className, + )} + style={{ + ...floatingStyles, + visibility: isPositioned ? 'visible' : 'hidden', + }} + > +
+ {memoryVarInNode.length > 0 && ( + <> +
+ +
{t('workflow.nodes.llm.memory.currentNodeLabel')}
+ +
+
+ {memoryVarInNode.map(variable => ( +
handleSelectVariable(['conversation', variable.name])}> + +
{variable.name}
+
+ ))} +
+ + )} + {memoryVarInApp.length > 0 && ( + <> +
+ +
{t('workflow.nodes.llm.memory.conversationScopeLabel')}
+ +
+
+ {memoryVarInApp.map(variable => ( +
handleSelectVariable(['conversation', variable.name])}> + +
{variable.name}
+
+ ))} +
+ + )} +
{t('workflow.nodes.llm.memory.createButton')}
+
+
, containerEl, ) 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 e9c89d0cb8..252d0e1060 100644 --- a/web/app/components/workflow/nodes/_base/components/prompt/editor.tsx +++ b/web/app/components/workflow/nodes/_base/components/prompt/editor.tsx @@ -37,6 +37,9 @@ 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 AddMemoryButton, { MEMORY_POPUP_SHOW_BY_EVENT_EMITTER } from './add-memory-button' +import type { + ConversationVariable, +} from '@/app/components/workflow/types' type Props = { className?: string @@ -81,6 +84,8 @@ type Props = { titleClassName?: string required?: boolean isMemorySupported?: boolean + memoryVarInNode?: ConversationVariable[] + memoryVarInApp?: ConversationVariable[] } const Editor: FC = ({ @@ -121,6 +126,8 @@ const Editor: FC = ({ editorContainerClassName, required, isMemorySupported, + memoryVarInNode = [], + memoryVarInApp = [], }) => { const { t } = useTranslation() const { eventEmitter } = useEventEmitterContextContext() @@ -301,6 +308,8 @@ const Editor: FC = ({ editable={!readOnly} isSupportFileVar={isSupportFileVar} isMemorySupported + memoryVarInNode={memoryVarInNode} + memoryVarInApp={memoryVarInApp} /> {/* 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..45786fb984 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 @@ -9,6 +9,9 @@ import Editor from '@/app/components/workflow/nodes/_base/components/prompt/edit import TypeSelector from '@/app/components/workflow/nodes/_base/components/selector' import Tooltip from '@/app/components/base/tooltip' import { PromptRole } from '@/models/debug' +import type { + ConversationVariable, +} from '@/app/components/workflow/types' const i18nPrefix = 'workflow.nodes.llm' @@ -39,6 +42,8 @@ type Props = { varList: Variable[] handleAddVariable: (payload: any) => void modelConfig?: ModelConfig + memoryVarInNode?: ConversationVariable[] + memoryVarInApp?: ConversationVariable[] } const roleOptions = [ @@ -81,6 +86,8 @@ const ConfigPromptItem: FC = ({ varList, handleAddVariable, modelConfig, + memoryVarInNode = [], + memoryVarInApp = [], }) => { const { t } = useTranslation() const workflowStore = useWorkflowStore() @@ -157,6 +164,8 @@ const ConfigPromptItem: FC = ({ } isMemorySupported + memoryVarInNode={memoryVarInNode} + memoryVarInApp={memoryVarInApp} /> ) } 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 120c5619e6..c585604d3b 100644 --- a/web/app/components/workflow/nodes/llm/components/config-prompt.tsx +++ b/web/app/components/workflow/nodes/llm/components/config-prompt.tsx @@ -14,6 +14,9 @@ import cn from '@/utils/classnames' import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor' import AddButton from '@/app/components/workflow/nodes/_base/components/add-button' import { DragHandle } from '@/app/components/base/icons/src/vender/line/others' +import type { + ConversationVariable, +} from '@/app/components/workflow/types' const i18nPrefix = 'workflow.nodes.llm' @@ -35,6 +38,8 @@ type Props = { handleAddVariable: (payload: any) => void modelConfig: ModelConfig memoryVarSortFn?: (a: string, b: string) => number + memoryVarInNode?: ConversationVariable[] + memoryVarInApp?: ConversationVariable[] } const ConfigPrompt: FC = ({ @@ -51,6 +56,8 @@ const ConfigPrompt: FC = ({ handleAddVariable, modelConfig, memoryVarSortFn, + memoryVarInNode, + memoryVarInApp, }) => { const { t } = useTranslation() const workflowStore = useWorkflowStore() @@ -208,6 +215,8 @@ const ConfigPrompt: FC = ({ varList={varList} handleAddVariable={handleAddVariable} modelConfig={modelConfig} + memoryVarInNode={memoryVarInNode} + memoryVarInApp={memoryVarInApp} />
) diff --git a/web/app/components/workflow/nodes/llm/panel.tsx b/web/app/components/workflow/nodes/llm/panel.tsx index 05580f6eba..e02b547637 100644 --- a/web/app/components/workflow/nodes/llm/panel.tsx +++ b/web/app/components/workflow/nodes/llm/panel.tsx @@ -65,6 +65,8 @@ const Panel: FC> = ({ filterJinja2InputVar, handleReasoningFormatChange, memoryVarSortFn, + memoryVarInNode, + memoryVarInApp, } = useConfig(id, data) const { memoryType } = useMemory(id, data) @@ -157,6 +159,8 @@ const Panel: FC> = ({ handleAddVariable={handleAddVariable} modelConfig={model} memoryVarSortFn={memoryVarSortFn} + memoryVarInNode={memoryVarInNode} + memoryVarInApp={memoryVarInApp} /> )} diff --git a/web/app/components/workflow/nodes/llm/use-config.ts b/web/app/components/workflow/nodes/llm/use-config.ts index ca444994fd..72f3f73260 100644 --- a/web/app/components/workflow/nodes/llm/use-config.ts +++ b/web/app/components/workflow/nodes/llm/use-config.ts @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import produce from 'immer' import { EditionType, VarType } from '../../types' import type { Memory, PromptItem, ValueSelector, Var, Variable } from '../../types' @@ -18,10 +18,12 @@ import { import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud' import { checkHasContextBlock, checkHasHistoryBlock, checkHasQueryBlock } from '@/app/components/base/prompt-editor/constants' import useInspectVarsCrud from '@/app/components/workflow/hooks/use-inspect-vars-crud' +import { ChatVarType } from '@/app/components/workflow/panel/chat-variable-panel/type' const useConfig = (id: string, payload: LLMNodeType) => { const { nodesReadOnly: readOnly } = useNodesReadOnly() const isChatMode = useIsChatMode() + const conversationVariables = useStore(s => s.conversationVariables) const defaultConfig = useStore(s => s.nodesDefaultConfigs)?.[payload.type] const [defaultRolePrefix, setDefaultRolePrefix] = useState<{ user: string; assistant: string }>({ user: '', assistant: '' }) @@ -342,6 +344,20 @@ const useConfig = (id: string, payload: LLMNodeType) => { return a.localeCompare(b) }, [inputs.memory?.block_id]) + const memoryVarInNode = useMemo(() => { + const idsInNode = inputs.memory?.block_id || [] + return conversationVariables + .filter(varItem => varItem.value_type === ChatVarType.Memory) + .filter(varItem => idsInNode.includes(varItem.id)) + }, [inputs.memory?.block_id, conversationVariables]) + + const memoryVarInApp = useMemo(() => { + const idsInApp = inputs.memory?.block_id || [] + return conversationVariables + .filter(varItem => varItem.value_type === ChatVarType.Memory) + .filter(varItem => !idsInApp.includes(varItem.id)) + }, [inputs.memory?.block_id, conversationVariables]) + return { readOnly, isChatMode, @@ -376,6 +392,8 @@ const useConfig = (id: string, payload: LLMNodeType) => { filterJinja2InputVar, handleReasoningFormatChange, memoryVarSortFn, + memoryVarInNode, + memoryVarInApp, } } diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index eb379111e8..0993dc98a9 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -526,6 +526,9 @@ const translation = { promptEditorPlaceholder2: 'Type \'/\' to insert variable', memory: { addButton: 'Add Memory', + currentNodeLabel: 'Current Node scope', + conversationScopeLabel: 'Conversation scope', + createButton: 'Create memory variable', }, }, knowledgeRetrieval: { diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index f1a0331dac..36646b7a13 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -526,6 +526,9 @@ const translation = { promptEditorPlaceholder2: '输入 \'/\' 插入变量', memory: { addButton: '添加记忆', + currentNodeLabel: '当前节点范围', + conversationScopeLabel: '会话范围', + createButton: '创建记忆变量', }, }, knowledgeRetrieval: {