feat: add AssembleVariablesAlt icon and integrate into sub-graph

components.
This commit is contained in:
zhsama
2026-01-19 22:29:28 +08:00
parent 1bdc47220b
commit f44305af0d
21 changed files with 611 additions and 252 deletions

View File

@ -351,6 +351,25 @@ const VarReferenceVars: FC<Props> = ({
)
}
{
showAssembleVariables && (
<div className="flex items-center border-t border-divider-subtle pt-1">
<button
type="button"
className="flex h-6 w-full items-center rounded-md pl-3 pr-[18px] text-text-secondary hover:bg-state-base-hover"
onClick={handleAssembleVariables}
onMouseDown={e => e.preventDefault()}
>
<span className="mr-1 flex h-4 w-4 items-center justify-center rounded bg-util-colors-blue-blue-500">
<AssembleVariables className="h-3 w-3 text-text-primary-on-surface" />
</span>
<span className="system-xs-medium truncate" title={t('nodes.tool.assembleVariables', { ns: 'workflow' })}>
{t('nodes.tool.assembleVariables', { ns: 'workflow' })}
</span>
</button>
</div>
)
}
{filteredVars.length > 0
? (
<div className={cn('max-h-[85vh] overflow-y-auto', maxHeightClass)}>
@ -404,25 +423,6 @@ const VarReferenceVars: FC<Props> = ({
/>
)
}
{
showAssembleVariables && (
<div className="flex items-center border-t border-divider-subtle pt-1">
<button
type="button"
className="flex h-6 w-full items-center rounded-md pl-3 pr-[18px] text-text-secondary hover:bg-state-base-hover"
onClick={handleAssembleVariables}
onMouseDown={e => e.preventDefault()}
>
<span className="mr-1 flex h-4 w-4 items-center justify-center rounded bg-util-colors-blue-blue-500">
<AssembleVariables className="h-3 w-3 text-text-primary-on-surface" />
</span>
<span className="system-xs-medium truncate" title={t('nodes.tool.assembleVariables', { ns: 'workflow' })}>
{t('nodes.tool.assembleVariables', { ns: 'workflow' })}
</span>
</button>
</div>
)
}
</>
)
}

View File

@ -0,0 +1 @@
export const CUSTOM_SUB_GRAPH_START_NODE = 'custom-sub-graph-start'

View File

@ -0,0 +1,60 @@
import type { NodeProps } from 'reactflow'
import type { CommonNodeType } from '@/app/components/workflow/types'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import { AssembleVariablesAlt } from '@/app/components/base/icons/src/vender/line/general'
import { Agent } from '@/app/components/base/icons/src/vender/workflow'
import Tooltip from '@/app/components/base/tooltip'
import { NodeSourceHandle } from '@/app/components/workflow/nodes/_base/components/node-handle'
import { cn } from '@/utils/classnames'
type SubGraphStartNodeData = CommonNodeType<{
tooltip?: string
iconType?: string
}>
type IconComponent = typeof Agent
const iconMap: Record<string, IconComponent> = {
agent: Agent,
assemble: AssembleVariablesAlt,
}
const SubGraphStartNode = ({ id, data }: NodeProps<SubGraphStartNodeData>) => {
const { t } = useTranslation()
const iconType = data?.iconType || 'agent'
const Icon = iconMap[iconType] || Agent
const rawTitle = data?.title?.trim() || ''
const showTitle = iconType === 'agent' && !!rawTitle
const displayTitle = showTitle && (rawTitle.startsWith('@') ? rawTitle : `@${rawTitle}`)
const tooltip = data?.tooltip
|| (iconType === 'assemble' ? t('blocks.start', { ns: 'workflow' }) : (data?.title || t('blocks.start', { ns: 'workflow' })))
return (
<div
className={cn(
'nodrag group mt-1 flex h-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-workflow-block-bg shadow-xs',
showTitle ? 'gap-1.5 px-2' : 'w-11',
)}
>
<Tooltip popupContent={tooltip} asChild={false}>
<div className="flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500">
<Icon className="h-3 w-3 text-text-primary-on-surface" />
</div>
</Tooltip>
{showTitle && (
<span className="system-xs-medium max-w-[160px] truncate text-text-secondary">
{displayTitle}
</span>
)}
<NodeSourceHandle
id={id}
data={data}
handleClassName="!top-1/2 !-right-[9px] !-translate-y-1/2"
handleId="source"
/>
</div>
)
}
export default memo(SubGraphStartNode)

View File

@ -2,6 +2,7 @@ import type { FC } from 'react'
import { RiCloseLine, RiEqualizer2Line } from '@remixicon/react'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import { AssembleVariables } from '@/app/components/base/icons/src/vender/line/general'
import AlertTriangle from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle'
import { Agent } from '@/app/components/base/icons/src/vender/workflow'
import { cn } from '@/utils/classnames'
@ -34,8 +35,11 @@ const AgentHeaderBar: FC<AgentHeaderBarProps> = ({
: 'border-components-panel-border-subtle bg-components-badge-white-to-dark',
)}
>
<div className="flex h-4 w-4 items-center justify-center rounded bg-util-colors-indigo-indigo-500">
<Agent className="h-3 w-3 text-text-primary-on-surface" />
<div className={cn('flex h-4 w-4 items-center justify-center rounded', showAtPrefix
? 'bg-util-colors-indigo-indigo-500'
: 'bg-util-colors-blue-blue-500')}
>
{showAtPrefix ? <Agent className="h-3 w-3 text-text-primary-on-surface" /> : <AssembleVariables className="h-3 w-3 text-text-primary-on-surface" />}
</div>
<span className="system-xs-medium text-text-secondary">
{showAtPrefix && '@'}

View File

@ -36,9 +36,16 @@ import Placeholder from './placeholder'
/**
* Matches agent context variable syntax: {{@nodeId.context@}}
* Example: {{@agent-123.context@}} -> captures "agent-123"
* Example: {{@agent-123.context@}}
*/
const AGENT_CONTEXT_VAR_PATTERN = /\{\{@([^.@#]+)\.context@\}\}/g
const AGENT_CONTEXT_VAR_PATTERN = /\{\{@[^.@#]+\.context@\}\}/g
const AGENT_CONTEXT_VAR_PREFIX = '{{@'
const AGENT_CONTEXT_VAR_SUFFIX = '.context@}}'
const getAgentNodeIdFromContextVar = (placeholder: string) => {
if (!placeholder.startsWith(AGENT_CONTEXT_VAR_PREFIX) || !placeholder.endsWith(AGENT_CONTEXT_VAR_SUFFIX))
return ''
return placeholder.slice(AGENT_CONTEXT_VAR_PREFIX.length, -AGENT_CONTEXT_VAR_SUFFIX.length)
}
const buildAssemblePlaceholder = (toolNodeId?: string, paramKey?: string) => {
if (!toolNodeId || !paramKey)
@ -309,8 +316,9 @@ const MixedVariableTextInput = ({
const matches = text.matchAll(AGENT_CONTEXT_VAR_PATTERN)
for (const match of matches) {
const variablePath = match[1]
const nodeId = variablePath.split('.')[0]
const nodeId = getAgentNodeIdFromContextVar(match[0])
if (!nodeId)
continue
const node = nodesByIdMap[nodeId]
if (node && contextNodeIds.has(nodeId)) {
return {
@ -461,8 +469,8 @@ const MixedVariableTextInput = ({
if (!agentNodeId || !onChange)
return
const valueWithoutAgentVars = value.replace(AGENT_CONTEXT_VAR_PATTERN, (match, variablePath) => {
const nodeId = variablePath.split('.')[0]
const valueWithoutAgentVars = value.replace(AGENT_CONTEXT_VAR_PATTERN, (match) => {
const nodeId = getAgentNodeIdFromContextVar(match)
return nodeId === agentNodeId ? '' : match
})
@ -552,6 +560,7 @@ const MixedVariableTextInput = ({
<AgentHeaderBar
agentName={t('nodes.tool.assembleVariables', { ns: 'workflow' })}
onRemove={handleAssembleRemove}
onViewInternals={handleOpenSubGraphModal}
hasWarning={hasAssembleWarning}
showAtPrefix={false}
/>
@ -599,10 +608,21 @@ const MixedVariableTextInput = ({
}}
/>
)}
{toolNodeId && detectedAgentFromValue && sourceVariable && (
{toolNodeId && paramKey && isAssembleValue && (
<SubGraphModal
isOpen={isSubGraphModalOpen}
onClose={handleCloseSubGraphModal}
variant="assemble"
toolNodeId={toolNodeId}
paramKey={paramKey}
title={t('nodes.tool.assembleVariables', { ns: 'workflow' })}
/>
)}
{toolNodeId && paramKey && !isAssembleValue && detectedAgentFromValue && sourceVariable && (
<SubGraphModal
isOpen={isSubGraphModalOpen}
onClose={handleCloseSubGraphModal}
variant="agent"
toolNodeId={toolNodeId}
paramKey={paramKey}
sourceVariable={sourceVariable}

View File

@ -2,6 +2,7 @@
import type { FC } from 'react'
import type { SubGraphModalProps } from './types'
import type { MentionConfig } from '@/app/components/workflow/nodes/_base/types'
import type { CodeNodeType } from '@/app/components/workflow/nodes/code/types'
import type { LLMNodeType } from '@/app/components/workflow/nodes/llm/types'
import type { ToolNodeType } from '@/app/components/workflow/nodes/tool/types'
import type { Node, PromptItem, PromptTemplateItem } from '@/app/components/workflow/types'
@ -11,24 +12,29 @@ import { noop } from 'es-toolkit/function'
import { Fragment, memo, useCallback, useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { useStore as useReactFlowStore, useStoreApi } from 'reactflow'
import { AssembleVariablesAlt } from '@/app/components/base/icons/src/vender/line/general'
import { Agent } from '@/app/components/base/icons/src/vender/workflow'
import { useIsChatMode, useNodesSyncDraft, useWorkflow, useWorkflowVariables } from '@/app/components/workflow/hooks'
import { useHooksStore } from '@/app/components/workflow/hooks-store'
import { VarKindType } from '@/app/components/workflow/nodes/_base/types'
import { useStore as useWorkflowStore } from '@/app/components/workflow/store'
import { BlockEnum, EditionType, isPromptMessageContext, PromptRole } from '@/app/components/workflow/types'
import { BlockEnum, EditionType, isPromptMessageContext, PromptRole, VarType } from '@/app/components/workflow/types'
import SubGraphCanvas from './sub-graph-canvas'
const SubGraphModal: FC<SubGraphModalProps> = ({
isOpen,
onClose,
toolNodeId,
paramKey,
sourceVariable,
agentName,
agentNodeId,
}) => {
const SubGraphModal: FC<SubGraphModalProps> = (props) => {
const { t } = useTranslation()
const { isOpen, onClose, variant, toolNodeId, paramKey } = props
const isAgentVariant = variant === 'agent'
const resolvedAgentNodeId = isAgentVariant ? props.agentNodeId : ''
const agentName = isAgentVariant ? props.agentName : ''
const assembleTitle = !isAgentVariant ? props.title : ''
const modalTitle = useMemo(() => {
const baseTitle = isAgentVariant
? agentName
: (assembleTitle || t('nodes.tool.assembleVariables', { ns: 'workflow' }))
const prefix = isAgentVariant && baseTitle ? '@' : ''
return `${prefix}${baseTitle} ${t('subGraphModal.title', { ns: 'workflow' })}`.trim()
}, [agentName, assembleTitle, isAgentVariant, t])
const reactflowStore = useStoreApi()
const workflowNodes = useWorkflowStore(state => state.nodes)
const workflowEdges = useReactFlowStore(state => state.edges)
@ -41,13 +47,16 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
const extractorNodeId = `${toolNodeId}_ext_${paramKey}`
const extractorNode = useMemo(() => {
return workflowNodes.find(node => node.id === extractorNodeId) as Node<LLMNodeType> | undefined
return workflowNodes.find(node => node.id === extractorNodeId) as Node<LLMNodeType | CodeNodeType> | undefined
}, [extractorNodeId, workflowNodes])
const toolNode = useMemo(() => {
return workflowNodes.find(node => node.id === toolNodeId)
}, [toolNodeId, workflowNodes])
const toolParam = (toolNode?.data as ToolNodeType | undefined)?.tool_parameters?.[paramKey]
const toolParamValue = toolParam?.value as string | undefined
const assemblePlaceholder = useMemo(() => {
return `{{#${toolNodeId}_ext_${paramKey}.result#}}`
}, [paramKey, toolNodeId])
const parentBeforeNodes = useMemo(() => {
if (!isOpen)
@ -56,25 +65,28 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
}, [getBeforeNodesInSameBranch, isOpen, toolNodeId, workflowEdges, workflowNodes])
const parentContextNodes = useMemo(() => {
if (!parentBeforeNodes.length)
if (!parentBeforeNodes.length || !isAgentVariant)
return []
return parentBeforeNodes.filter(node => node.data.type === BlockEnum.Agent || node.data.type === BlockEnum.LLM)
}, [parentBeforeNodes])
}, [isAgentVariant, parentBeforeNodes])
const parentContextNodeIds = useMemo(() => {
return parentContextNodes.map(node => node.id)
}, [parentContextNodes])
const parentAvailableNodes = useMemo(() => {
if (!isOpen)
return []
return isAgentVariant ? parentContextNodes : parentBeforeNodes
}, [isAgentVariant, isOpen, parentBeforeNodes, parentContextNodes])
const parentAvailableVars = useMemo(() => {
if (!parentContextNodeIds.length)
if (!parentAvailableNodes.length)
return []
const vars = getNodeAvailableVars({
beforeNodes: parentContextNodes,
beforeNodes: parentAvailableNodes,
isChatMode,
filterVar: () => true,
})
return vars.filter(nodeVar => parentContextNodeIds.includes(nodeVar.nodeId))
}, [getNodeAvailableVars, isChatMode, parentContextNodeIds, parentContextNodes])
const availableNodeIds = new Set(parentAvailableNodes.map(node => node.id))
return vars.filter(nodeVar => availableNodeIds.has(nodeVar.nodeId))
}, [getNodeAvailableVars, isChatMode, parentAvailableNodes])
const mentionConfig = useMemo<MentionConfig>(() => {
const current = toolParam?.mention_config
@ -91,6 +103,9 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
}, [extractorNodeId, paramKey, toolParam?.mention_config])
const handleMentionConfigChange = useCallback((config: MentionConfig) => {
if (!isAgentVariant)
return
const { getNodes, setNodes } = reactflowStore.getState()
const nextNodes = getNodes().map((node) => {
if (node.id !== toolNodeId)
@ -118,10 +133,10 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
})
setNodes(nextNodes)
handleSyncWorkflowDraft()
}, [handleSyncWorkflowDraft, paramKey, reactflowStore, toolNodeId])
}, [handleSyncWorkflowDraft, isAgentVariant, paramKey, reactflowStore, toolNodeId])
useEffect(() => {
if (!toolParam || (toolParam.type && toolParam.type !== VarKindType.mention))
if (!isAgentVariant || !toolParam || (toolParam.type && toolParam.type !== VarKindType.mention))
return
const current = toolParam.mention_config
@ -132,7 +147,7 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
if (needsExtractor || needsNullStrategy || needsOutputSelector || needsDefaultValue)
handleMentionConfigChange(mentionConfig)
}, [handleMentionConfigChange, mentionConfig, toolParam])
}, [handleMentionConfigChange, isAgentVariant, mentionConfig, toolParam])
const getUserPromptText = useCallback((promptTemplate?: PromptTemplateItem[] | PromptItem) => {
if (!promptTemplate)
@ -156,23 +171,46 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
// TODO: handle external workflow updates while sub-graph modal is open.
const handleSave = useCallback((subGraphNodes: Node[]) => {
const extractorNodeData = subGraphNodes.find(node => node.id === extractorNodeId) as Node<LLMNodeType> | undefined
const extractorNodeData = subGraphNodes.find(node => node.id === extractorNodeId) as Node<LLMNodeType | CodeNodeType> | undefined
if (!extractorNodeData)
return
const userPromptText = getUserPromptText(extractorNodeData.data?.prompt_template)
const placeholder = `{{@${agentNodeId}.context@}}`
const nextValue = `${placeholder}${userPromptText}`
const ensureAssembleOutputs = (payload: CodeNodeType) => {
const outputs = payload.outputs || {}
if (outputs.result)
return payload
return {
...payload,
outputs: {
...outputs,
result: {
type: VarType.string,
children: null,
},
},
}
}
const userPromptText = isAgentVariant
? getUserPromptText((extractorNodeData.data as LLMNodeType).prompt_template)
: ''
const placeholder = isAgentVariant && resolvedAgentNodeId ? `{{@${resolvedAgentNodeId}.context@}}` : ''
const nextValue = isAgentVariant
? `${placeholder}${userPromptText}`
: assemblePlaceholder
const { getNodes, setNodes } = reactflowStore.getState()
const nextNodes = getNodes().map((node) => {
if (node.id === extractorNodeId) {
const nextData = isAgentVariant
? extractorNodeData.data
: ensureAssembleOutputs(extractorNodeData.data as CodeNodeType)
return {
...node,
hidden: true,
data: {
...node.data,
...extractorNodeData.data,
...nextData,
parent_node_id: toolNodeId,
},
}
@ -200,7 +238,7 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
})
setNodes(nextNodes)
setControlPromptEditorRerenderKey(Date.now())
}, [agentNodeId, extractorNodeId, getUserPromptText, paramKey, reactflowStore, setControlPromptEditorRerenderKey, toolNodeId])
}, [assemblePlaceholder, extractorNodeId, getUserPromptText, isAgentVariant, paramKey, reactflowStore, resolvedAgentNodeId, setControlPromptEditorRerenderKey, toolNodeId])
return (
<Transition appear show={isOpen} as={Fragment}>
@ -215,13 +253,12 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
<div className="flex h-14 shrink-0 items-center justify-between border-b border-divider-subtle px-4">
<div className="flex items-center gap-2">
<div className="flex h-6 w-6 items-center justify-center rounded bg-util-colors-indigo-indigo-500">
<Agent className="h-4 w-4 text-text-primary-on-surface" />
{isAgentVariant
? <Agent className="h-4 w-4 text-text-primary-on-surface" />
: <AssembleVariablesAlt className="h-4 w-4 text-text-primary-on-surface" />}
</div>
<span className="system-md-semibold text-text-primary">
@
{agentName}
{' '}
{t('subGraphModal.title', { ns: 'workflow' })}
{modalTitle}
</span>
</div>
<button
@ -234,22 +271,41 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
</div>
<div className="bg-workflow-canvas-wrapper relative flex-1 overflow-hidden">
<SubGraphCanvas
toolNodeId={toolNodeId}
paramKey={paramKey}
sourceVariable={sourceVariable}
agentNodeId={agentNodeId}
agentName={agentName}
configsMap={configsMap}
mentionConfig={mentionConfig}
onMentionConfigChange={handleMentionConfigChange}
extractorNode={extractorNode}
toolParamValue={toolParamValue}
parentAvailableNodes={parentContextNodes}
parentAvailableVars={parentAvailableVars}
onSave={handleSave}
onSyncWorkflowDraft={doSyncWorkflowDraft}
/>
{variant === 'agent'
? (
<SubGraphCanvas
variant="agent"
toolNodeId={toolNodeId}
paramKey={paramKey}
sourceVariable={props.sourceVariable}
agentNodeId={props.agentNodeId}
agentName={props.agentName}
configsMap={configsMap}
mentionConfig={mentionConfig}
onMentionConfigChange={handleMentionConfigChange}
extractorNode={extractorNode as Node<LLMNodeType> | undefined}
toolParamValue={toolParamValue}
parentAvailableNodes={parentAvailableNodes}
parentAvailableVars={parentAvailableVars}
onSave={handleSave}
onSyncWorkflowDraft={doSyncWorkflowDraft}
/>
)
: (
<SubGraphCanvas
variant="assemble"
toolNodeId={toolNodeId}
paramKey={paramKey}
title={props.title}
configsMap={configsMap}
extractorNode={extractorNode as Node<CodeNodeType> | undefined}
toolParamValue={toolParamValue}
parentAvailableNodes={parentAvailableNodes}
parentAvailableVars={parentAvailableVars}
onSave={handleSave}
onSyncWorkflowDraft={doSyncWorkflowDraft}
/>
)}
</div>
</DialogPanel>
</TransitionChild>

View File

@ -4,40 +4,10 @@ import type { SubGraphCanvasProps } from './types'
import { memo } from 'react'
import SubGraph from '@/app/components/sub-graph'
const SubGraphCanvas: FC<SubGraphCanvasProps> = ({
toolNodeId,
paramKey,
sourceVariable,
agentNodeId,
agentName,
configsMap,
mentionConfig,
onMentionConfigChange,
extractorNode,
toolParamValue,
parentAvailableNodes,
parentAvailableVars,
onSave,
onSyncWorkflowDraft,
}) => {
const SubGraphCanvas: FC<SubGraphCanvasProps> = (props) => {
return (
<div className="h-full w-full">
<SubGraph
toolNodeId={toolNodeId}
paramKey={paramKey}
sourceVariable={sourceVariable}
agentNodeId={agentNodeId}
agentName={agentName}
configsMap={configsMap}
mentionConfig={mentionConfig}
onMentionConfigChange={onMentionConfigChange}
extractorNode={extractorNode}
toolParamValue={toolParamValue}
parentAvailableNodes={parentAvailableNodes}
parentAvailableVars={parentAvailableVars}
onSave={onSave}
onSyncWorkflowDraft={onSyncWorkflowDraft}
/>
<SubGraph {...props} />
</div>
)
}

View File

@ -1,34 +1,25 @@
import type { SyncWorkflowDraft } from '@/app/components/sub-graph/types'
import type { Shape as HooksStoreShape } from '@/app/components/workflow/hooks-store'
import type { MentionConfig } from '@/app/components/workflow/nodes/_base/types'
import type { LLMNodeType } from '@/app/components/workflow/nodes/llm/types'
import type { NodeOutPutVar, Edge as WorkflowEdge, Node as WorkflowNode } from '@/app/components/workflow/types'
import type { SubGraphProps } from '@/app/components/sub-graph/types'
import type { ValueSelector } from '@/app/components/workflow/types'
type WorkflowValueSelector = string[]
export type SubGraphModalProps = {
type BaseSubGraphModalProps = {
isOpen: boolean
onClose: () => void
toolNodeId: string
paramKey: string
sourceVariable: WorkflowValueSelector
}
type AgentSubGraphModalProps = BaseSubGraphModalProps & {
variant: 'agent'
sourceVariable: ValueSelector
agentName: string
agentNodeId: string
}
export type SubGraphCanvasProps = {
toolNodeId: string
paramKey: string
sourceVariable: WorkflowValueSelector
agentNodeId: string
agentName: string
configsMap?: HooksStoreShape['configsMap']
mentionConfig: MentionConfig
onMentionConfigChange: (config: MentionConfig) => void
extractorNode?: WorkflowNode<LLMNodeType>
toolParamValue?: string
parentAvailableNodes?: WorkflowNode[]
parentAvailableVars?: NodeOutPutVar[]
onSave?: (nodes: WorkflowNode[], edges: WorkflowEdge[]) => void
onSyncWorkflowDraft?: SyncWorkflowDraft
type AssembleSubGraphModalProps = BaseSubGraphModalProps & {
variant: 'assemble'
title: string
}
export type SubGraphModalProps = AgentSubGraphModalProps | AssembleSubGraphModalProps
export type SubGraphCanvasProps = SubGraphProps

View File

@ -20,7 +20,14 @@ import { useStrategyProviders } from '@/service/use-strategy'
import { cn } from '@/utils/classnames'
import { VarType } from './types'
const AGENT_CONTEXT_VAR_PATTERN = /\{\{@([^.@#]+)\.context@\}\}/g
const AGENT_CONTEXT_VAR_PATTERN = /\{\{@[^.@#]+\.context@\}\}/g
const AGENT_CONTEXT_VAR_PREFIX = '{{@'
const AGENT_CONTEXT_VAR_SUFFIX = '.context@}}'
const getAgentNodeIdFromContextVar = (placeholder: string) => {
if (!placeholder.startsWith(AGENT_CONTEXT_VAR_PREFIX) || !placeholder.endsWith(AGENT_CONTEXT_VAR_SUFFIX))
return ''
return placeholder.slice(AGENT_CONTEXT_VAR_PREFIX.length, -AGENT_CONTEXT_VAR_SUFFIX.length)
}
type AgentCheckValidContext = {
provider?: StrategyPluginDetail
strategy?: StrategyDetail
@ -80,7 +87,7 @@ const Node: FC<NodeProps<ToolNodeType>> = ({
return
const matches = value.matchAll(AGENT_CONTEXT_VAR_PATTERN)
for (const match of matches) {
const agentNodeId = match[1]
const agentNodeId = getAgentNodeIdFromContextVar(match[0])
if (!agentNodeId)
continue
const entryKey = `${paramKey}:${agentNodeId}`