fix: memory variable item

This commit is contained in:
zxhlyh 2025-11-04 17:53:51 +08:00
parent 2944f831e2
commit 9d310fed92
8 changed files with 132 additions and 13 deletions

View File

@ -85,9 +85,11 @@ export const useNodesSyncDraft = () => {
},
environment_variables: environmentVariables,
conversation_variables: conversationVariables,
memory_blocks: memoryVariables.map(({ value_type, more, model, ...rest }) => {
memory_blocks: memoryVariables.map(({ value_type, scope, more, node_id, model, ...rest }) => {
return {
...rest,
node_id: scope === 'node' ? node_id : undefined,
scope,
model: model ? {
completion_params: model.completion_params,
mode: model.mode,

View File

@ -1,4 +1,6 @@
import { useCallback } from 'react'
import {
useCallback,
} from 'react'
import {
useStore,
useWorkflowStore,

View File

@ -14,6 +14,7 @@ import { useMemoryVariables } from './hooks/use-memory-variables'
import Confirm from '@/app/components/base/confirm'
import { Memory as MemoryIcon } from '@/app/components/base/icons/src/vender/line/others'
import VariableModal from '@/app/components/workflow/panel/chat-variable-panel/components/variable-modal'
import cn from '@/utils/classnames'
type BlockMemoryProps = {
id: string
@ -21,6 +22,7 @@ type BlockMemoryProps = {
}
const BlockMemory = ({ id }: BlockMemoryProps) => {
const { t } = useTranslation()
const [destructiveItemId, setDestructiveItemId] = useState<string | undefined>(undefined)
const {
memoryVariablesInUsed,
editMemoryVariable,
@ -55,7 +57,10 @@ const BlockMemory = ({ id }: BlockMemoryProps) => {
memoryVariablesInUsed.map(memoryVariable => (
<div
key={memoryVariable.id}
className='group flex h-8 items-center space-x-1 rounded-lg border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg pl-2 pr-1 shadow-xs hover:border hover:border-state-destructive-solid hover:bg-state-destructive-hover'>
className={cn(
'group flex h-8 items-center space-x-1 rounded-lg border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg pl-2 pr-1 shadow-xs',
destructiveItemId === memoryVariable.id && 'border border-state-destructive-solid bg-state-destructive-hover',
)}>
<MemoryIcon className='h-4 w-4 text-util-colors-teal-teal-700' />
<div
title={memoryVariable.name}
@ -63,22 +68,30 @@ const BlockMemory = ({ id }: BlockMemoryProps) => {
>
{memoryVariable.name}
</div>
<Badge className='shrink-0'>
<Badge className={cn('shrink-0 group-hover:hidden', editMemoryVariable?.id === memoryVariable.id && 'hidden')}>
{memoryVariable.term}
</Badge>
<ActionButton
className='hidden shrink-0 group-hover:block'
className={cn(
'hidden shrink-0 group-hover:inline-flex',
editMemoryVariable?.id === memoryVariable.id && 'inline-flex bg-state-base-hover text-text-secondary',
)}
size='m'
onClick={() => handleSetEditMemoryVariable(memoryVariable.id)}
>
<RiEditLine className='h-4 w-4 text-text-tertiary' />
</ActionButton>
<ActionButton
className='hidden shrink-0 group-hover:block'
className={cn(
'hidden shrink-0 bg-transparent hover:bg-transparent hover:text-text-destructive group-hover:inline-flex',
editMemoryVariable?.id === memoryVariable.id && 'inline-flex',
)}
size='m'
onClick={() => handleDelete(memoryVariable.id)}
onMouseOver={() => setDestructiveItemId(memoryVariable.id)}
onMouseOut={() => setDestructiveItemId(undefined)}
>
<RiDeleteBinLine className='h-4 w-4 text-text-destructive' />
<RiDeleteBinLine className={cn('h-4 w-4', destructiveItemId === memoryVariable.id && 'text-text-destructive')} />
</ActionButton>
</div>
))

View File

@ -0,0 +1,54 @@
import { memo } from 'react'
import { useStore } from 'reactflow'
import VariableItem from './variable-item'
import BlockIcon from '@/app/components/workflow/block-icon'
import { BlockEnum } from '@/app/components/workflow/types'
import type { MemoryVariable } from '@/app/components/workflow/types'
type VariableItemWithNodeProps = {
nodeId: string
memoryVariables: MemoryVariable[]
onEdit: (memoryVariable: MemoryVariable) => void
onDelete: (memoryVariable: MemoryVariable) => void
currentVarId?: string
}
const VariableItemWithNode = ({
nodeId,
memoryVariables,
onEdit,
onDelete,
currentVarId,
}: VariableItemWithNodeProps) => {
const currentNode = useStore(s => s.nodeInternals.get(nodeId))
if (!currentNode) return null
return (
<div className='space-y-1 py-1'>
<div className='mb-1 flex items-center'>
<BlockIcon className='mr-1.5 shrink-0' type={BlockEnum.LLM} />
<div
className='system-sm-medium grow truncate text-text-secondary'
title={currentNode?.data.title}
>
{currentNode?.data.title}
</div>
</div>
{
memoryVariables.map(memoryVariable => (
<VariableItem
key={memoryVariable.id}
item={memoryVariable}
onEdit={onEdit}
onDelete={onDelete}
scope='node'
term={memoryVariable.term}
currentVarId={currentVarId}
/>
))
}
</div>
)
}
export default memo(VariableItemWithNode)

View File

@ -8,17 +8,24 @@ import {
import type { ConversationVariable, MemoryVariable } from '@/app/components/workflow/types'
import cn from '@/utils/classnames'
import { ChatVarType } from '../type'
import Badge from '@/app/components/base/badge'
type VariableItemProps = {
item: ConversationVariable | MemoryVariable
onEdit: (item: ConversationVariable | MemoryVariable) => void
onDelete: (item: ConversationVariable | MemoryVariable) => void
scope?: string
term?: string
currentVarId?: string
}
const VariableItem = ({
item,
onEdit,
onDelete,
scope,
term,
currentVarId,
}: VariableItemProps) => {
const [destructive, setDestructive] = useState(false)
return (
@ -26,7 +33,7 @@ const VariableItem = ({
'radius-md mb-1 border border-components-panel-border-subtle bg-components-panel-on-panel-item-bg px-2.5 py-2 shadow-xs hover:bg-components-panel-on-panel-item-bg-hover',
destructive && 'border-state-destructive-border hover:bg-state-destructive-hover',
)}>
<div className='flex items-center justify-between'>
<div className='group flex items-center justify-between'>
<div className='flex grow items-center gap-1'>
{
item.value_type === ChatVarType.Memory && (
@ -42,16 +49,20 @@ const VariableItem = ({
<div className='system-xs-medium text-text-tertiary'>{capitalize(item.value_type)}</div>
</div>
<div className='flex shrink-0 items-center gap-1 text-text-tertiary'>
<div className='radius-md cursor-pointer p-1 hover:bg-state-base-hover hover:text-text-secondary'>
<div className={cn('radius-md hidden cursor-pointer p-1 hover:bg-state-base-hover hover:text-text-secondary group-hover:block', currentVarId === item.id && 'block bg-state-base-hover text-text-secondary')}>
<RiEditLine className='h-4 w-4' onClick={() => onEdit(item)}/>
</div>
<div
className='radius-md cursor-pointer p-1 hover:bg-state-destructive-hover hover:text-text-destructive'
className={cn('radius-md hidden cursor-pointer p-1 hover:bg-state-destructive-hover hover:text-text-destructive group-hover:block', currentVarId === item.id && 'block')}
onMouseOver={() => setDestructive(true)}
onMouseOut={() => setDestructive(false)}
>
<RiDeleteBinLine className='h-4 w-4' onClick={() => onDelete(item)}/>
</div>
<div className={cn('flex h-6 items-center gap-0.5 group-hover:hidden', currentVarId === item.id && 'hidden')}>
{scope && <Badge text={scope} />}
{term && <Badge text={term} />}
</div>
</div>
</div>
{

View File

@ -3,6 +3,7 @@ import {
useCallback,
useState,
} from 'react'
import { groupBy } from 'lodash-es'
import {
useStoreApi,
} from 'reactflow'
@ -30,16 +31,24 @@ import cn from '@/utils/classnames'
import useInspectVarsCrud from '../../hooks/use-inspect-vars-crud'
import { ChatVarType } from './type'
import { useMemoryVariable } from '@/app/components/workflow/hooks'
import VariableItemWithNode from './components/variable-item-with-node'
const ChatVariablePanel = () => {
const { t } = useTranslation()
const docLink = useDocLink()
const store = useStoreApi()
const workflowStore = useWorkflowStore()
const { handleAddMemoryVariable, handleUpdateMemoryVariable, handleDeleteMemoryVariable } = useMemoryVariable()
const appScopeMemoryVariables = useStore(s => s.memoryVariables.filter(v => v.scope === 'app'))
const nodeScopeMemoryVariables = useStore((s) => {
return groupBy(s.memoryVariables.filter(v => v.scope === 'node'), 'node_id')
})
const {
handleAddMemoryVariable,
handleUpdateMemoryVariable,
handleDeleteMemoryVariable,
} = useMemoryVariable()
const setShowChatVariablePanel = useStore(s => s.setShowChatVariablePanel)
const varList = useStore(s => s.conversationVariables) as ConversationVariable[]
const memoryVariables = useStore(s => s.memoryVariables) as MemoryVariable[]
const updateChatVarList = useStore(s => s.setConversationVariables)
const setMemoryVariables = useStore(s => s.setMemoryVariables)
const { doSyncWorkflowDraft } = useNodesSyncDraft()
@ -220,12 +229,15 @@ const ChatVariablePanel = () => {
</div>
<div className='grow overflow-y-auto rounded-b-2xl px-4'>
{
memoryVariables.map(memoryVariable => (
appScopeMemoryVariables.map(memoryVariable => (
<VariableItem
key={memoryVariable.id}
item={memoryVariable}
onEdit={handleEdit}
onDelete={deleteCheck}
term={memoryVariable.term}
scope='conv'
currentVarId={currentVar?.id}
/>
))
}
@ -235,8 +247,31 @@ const ChatVariablePanel = () => {
item={chatVar}
onEdit={handleEdit}
onDelete={deleteCheck}
currentVarId={currentVar?.id}
/>
))}
{
!!Object.keys(nodeScopeMemoryVariables).length && (
<div className='pb-1 pt-4'>
<div className='system-xs-medium-uppercase mb-1 flex items-center space-x-2 text-text-tertiary'>
{t('workflow.chatVariable.nodeScopeMemory')}
<div className='ml-2 h-px grow bg-gradient-to-r from-divider-regular to-background-gradient-mask-transparent'></div>
</div>
{
Object.keys(nodeScopeMemoryVariables).map(nodeId => (
<VariableItemWithNode
key={nodeId}
nodeId={nodeId}
memoryVariables={nodeScopeMemoryVariables[nodeId]}
onEdit={handleEdit}
onDelete={deleteCheck}
currentVarId={currentVar?.id}
/>
))
}
</div>
)
}
</div>
<RemoveEffectVarConfirm
isShow={showRemoveVarConfirm}

View File

@ -149,6 +149,7 @@ const translation = {
panelDescription: 'Conversation Variables are used to store interactive information that LLM needs to remember, including conversation history, uploaded files, user preferences. They are read-write. ',
docLink: 'Visit our docs to learn more.',
button: 'Add Variable',
nodeScopeMemory: 'Node Scope Memory',
modal: {
title: 'Add Conversation Variable',
editTitle: 'Edit Conversation Variable',

View File

@ -149,6 +149,7 @@ const translation = {
panelDescription: '会话变量用于存储 LLM 需要的上下文信息,如用户偏好、对话历史等。它是可读写的。',
docLink: '查看文档了解更多。',
button: '添加变量',
nodeScopeMemory: '节点范围记忆',
modal: {
title: '添加会话变量',
editTitle: '编辑会话变量',