Merge remote-tracking branch 'origin/feat/support-agent-sandbox' into pre-align-hitl-frontend

This commit is contained in:
yyh
2026-02-09 16:08:13 +08:00
8 changed files with 234 additions and 88 deletions

View File

@@ -333,6 +333,10 @@ const PromptEditorContent: FC<PromptEditorContentProps> = ({
}
}, [availableNodes, nodeId, onToolMetadataChange, toolMetadata, workflowVariableBlock?.variables])
const filePreviewContextValue = React.useMemo(() => ({
enabled: Boolean(isSupportSandbox),
}), [isSupportSandbox])
const sandboxPlaceHolder = React.useMemo(() => {
if (!isSupportSandbox)
return null
@@ -387,7 +391,7 @@ const PromptEditorContent: FC<PromptEditorContentProps> = ({
return (
<LexicalComposer initialConfig={{ ...initialConfig, editable }}>
<ToolBlockContextProvider value={toolBlockContextValue}>
<FilePreviewContextProvider value={{ enabled: Boolean(isSupportSandbox) }}>
<FilePreviewContextProvider value={filePreviewContextValue}>
<div
className={cn('relative', wrapperClassName)}
data-skill-editor-root={isSupportSandbox ? 'true' : undefined}

View File

@@ -94,6 +94,8 @@ const SkillEditor = ({
onAutoFocus,
toolPickerScope = 'all',
}: SkillEditorProps) => {
const filePreviewContextValue = React.useMemo(() => ({ enabled: false }), [])
const initialConfig = {
namespace: 'skill-editor',
nodes: [
@@ -123,7 +125,7 @@ const SkillEditor = ({
return (
<LexicalComposer initialConfig={{ ...initialConfig, editable }}>
<FilePreviewContextProvider value={{ enabled: false }}>
<FilePreviewContextProvider value={filePreviewContextValue}>
<div
className={cn('relative', showLineNumbers && styles.lineNumbersScope, wrapperClassName)}
data-skill-editor-root="true"

View File

@@ -45,7 +45,7 @@ const FileReferenceBlock = ({ nodeKey, resourceId }: FileReferenceBlockProps) =>
const [previewOpen, setPreviewOpen] = useState(false)
const [previewStyle, setPreviewStyle] = useState<React.CSSProperties | null>(null)
const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const { enabled: isPreviewEnabled } = useFilePreviewContext()
const isPreviewEnabled = useFilePreviewContext(context => context.enabled)
const { t } = useTranslation()
const isInteractive = editor.isEditable()

View File

@@ -1,13 +1,62 @@
import * as React from 'react'
import type { ReactNode } from 'react'
import { createContext, useCallback, useContext, useEffect, useRef } from 'react'
import { useStore } from 'zustand'
import { createStore } from 'zustand/vanilla'
type FilePreviewContextValue = {
export type FilePreviewContextValue = {
enabled: boolean
}
const FilePreviewContext = React.createContext<FilePreviewContextValue>({ enabled: false })
export const FilePreviewContextProvider = FilePreviewContext.Provider
export const useFilePreviewContext = () => {
return React.useContext(FilePreviewContext)
type FilePreviewStoreState = {
enabled: boolean
setEnabled: (enabled: boolean) => void
}
const createFilePreviewStore = (enabled: boolean) => createStore<FilePreviewStoreState>(set => ({
enabled,
setEnabled: nextEnabled => set({ enabled: nextEnabled }),
}))
type FilePreviewStore = ReturnType<typeof createFilePreviewStore>
const defaultFilePreviewStore = createFilePreviewStore(false)
const FilePreviewStoreContext = createContext<FilePreviewStore | null>(null)
type FilePreviewContextProviderProps = {
value?: FilePreviewContextValue
children: ReactNode
}
export const FilePreviewContextProvider = ({ value, children }: FilePreviewContextProviderProps) => {
const storeRef = useRef<FilePreviewStore>(null)
if (!storeRef.current)
storeRef.current = createFilePreviewStore(value?.enabled ?? false)
useEffect(() => {
storeRef.current?.getState().setEnabled(value?.enabled ?? false)
}, [value?.enabled])
return (
<FilePreviewStoreContext.Provider value={storeRef.current}>
{children}
</FilePreviewStoreContext.Provider>
)
}
// eslint-disable-next-line react-refresh/only-export-components
export const useFilePreviewContext = <T = FilePreviewContextValue>(
selector?: (context: FilePreviewContextValue) => T,
) => {
const store = useContext(FilePreviewStoreContext) ?? defaultFilePreviewStore
const selectContext = useCallback(
(state: FilePreviewStoreState) => {
if (selector)
return selector({ enabled: state.enabled })
return { enabled: state.enabled } as T
},
[selector],
)
return useStore(store, selectContext)
}

View File

@@ -9,6 +9,7 @@ import * as React from 'react'
import { useEffect, useMemo, useState } from 'react'
import { createPortal } from 'react-dom'
import { useTranslation } from 'react-i18next'
import { useShallow } from 'zustand/react/shallow'
import AppIcon from '@/app/components/base/app-icon'
import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
import Modal from '@/app/components/base/modal'
@@ -127,9 +128,25 @@ const ToolBlockComponent = ({
const { t } = useTranslation()
const authBadgeLabel = t('skillEditor.authorizationBadge', { ns: 'workflow' })
const { theme } = useTheme()
const toolBlockContext = useToolBlockContext()
const isUsingExternalMetadata = Boolean(toolBlockContext?.onMetadataChange)
const useModal = Boolean(toolBlockContext?.useModal)
const {
metadata,
onMetadataChange,
useModal,
nodeId: contextNodeId,
nodesOutputVars,
availableNodes,
} = useToolBlockContext(
useShallow(context => ({
metadata: context?.metadata,
onMetadataChange: context?.onMetadataChange,
useModal: context?.useModal,
nodeId: context?.nodeId,
nodesOutputVars: context?.nodesOutputVars,
availableNodes: context?.availableNodes,
})),
)
const isUsingExternalMetadata = Boolean(onMetadataChange)
const useModalValue = Boolean(useModal)
const [isSettingOpen, setIsSettingOpen] = useState(false)
const [toolValue, setToolValue] = useState<ToolValue | null>(null)
const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(null)
@@ -183,14 +200,14 @@ const ToolBlockComponent = ({
const toolConfigFromMetadata = useMemo(() => {
if (isUsingExternalMetadata) {
const metadata = toolBlockContext?.metadata as SkillFileMetadata | undefined
return metadata?.tools?.[configId]
const externalMetadata = metadata as SkillFileMetadata | undefined
return externalMetadata?.tools?.[configId]
}
if (!activeTabId || activeTabId === START_TAB_ID)
return undefined
const metadata = fileMetadata.get(activeTabId) as SkillFileMetadata | undefined
return metadata?.tools?.[configId]
}, [activeTabId, configId, fileMetadata, isUsingExternalMetadata, toolBlockContext?.metadata])
const resultMetadata = fileMetadata.get(activeTabId) as SkillFileMetadata | undefined
return resultMetadata?.tools?.[configId]
}, [activeTabId, configId, fileMetadata, isUsingExternalMetadata, metadata])
const isInteractive = editor.isEditable()
@@ -281,7 +298,7 @@ const ToolBlockComponent = ({
}, [configuredToolValue, isSettingOpen])
useEffect(() => {
if (useModal)
if (useModalValue)
return
const containerFromRef = ref.current?.closest('[data-skill-editor-root="true"]') as HTMLElement | null
const fallbackContainer = document.querySelector('[data-skill-editor-root="true"]') as HTMLElement | null
@@ -289,10 +306,10 @@ const ToolBlockComponent = ({
if (container)
// eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect
setPortalContainer(container)
}, [ref, useModal])
}, [ref, useModalValue])
useEffect(() => {
if (!isSettingOpen || useModal)
if (!isSettingOpen || useModalValue)
return
const handleClickOutside = (event: MouseEvent) => {
@@ -316,7 +333,7 @@ const ToolBlockComponent = ({
document.addEventListener('mousedown', handleClickOutside)
return () => document.removeEventListener('mousedown', handleClickOutside)
}, [isSettingOpen, portalContainer, ref, useModal])
}, [isSettingOpen, portalContainer, ref, useModalValue])
const displayLabel = label || toolMeta?.label || tool
const resolvedIcon = (() => {
@@ -398,7 +415,7 @@ const ToolBlockComponent = ({
return
const credentialId = normalizeCredentialId(nextValue.credential_id)
if (isUsingExternalMetadata) {
const metadata = (toolBlockContext?.metadata || {}) as SkillFileMetadata
const externalMetadata = (metadata || {}) as SkillFileMetadata
const toolType = currentProvider.type === CollectionType.mcp ? 'mcp' : 'builtin'
const buildFields = (value: Record<string, unknown> | undefined) => {
if (!value)
@@ -415,9 +432,9 @@ const ToolBlockComponent = ({
...buildFields(nextValue.parameters),
]
const nextMetadata: SkillFileMetadata = {
...metadata,
...externalMetadata,
tools: {
...(metadata.tools || {}),
...(externalMetadata.tools || {}),
[configId]: {
type: toolType,
configuration: { fields },
@@ -425,12 +442,12 @@ const ToolBlockComponent = ({
},
},
}
toolBlockContext?.onMetadataChange?.(nextMetadata)
onMetadataChange?.(nextMetadata)
return
}
if (!activeTabId || activeTabId === START_TAB_ID)
return
const metadata = (fileMetadata.get(activeTabId) || {}) as SkillFileMetadata
const currentMetadata = (fileMetadata.get(activeTabId) || {}) as SkillFileMetadata
const toolType = currentProvider.type === CollectionType.mcp ? 'mcp' : 'builtin'
const buildFields = (value: Record<string, unknown> | undefined) => {
if (!value)
@@ -447,9 +464,9 @@ const ToolBlockComponent = ({
...buildFields(nextValue.parameters),
]
const nextMetadata: SkillFileMetadata = {
...metadata,
...currentMetadata,
tools: {
...(metadata.tools || {}),
...(currentMetadata.tools || {}),
[configId]: {
type: toolType,
configuration: { fields },
@@ -488,13 +505,13 @@ const ToolBlockComponent = ({
return nextMetadata
}
if (isUsingExternalMetadata) {
toolBlockContext?.onMetadataChange?.(applyCredential(toolBlockContext?.metadata as SkillFileMetadata | undefined))
onMetadataChange?.(applyCredential(metadata as SkillFileMetadata | undefined))
return
}
if (!activeTabId || activeTabId === START_TAB_ID)
return
const metadata = fileMetadata.get(activeTabId) as SkillFileMetadata | undefined
const nextMetadata = applyCredential(metadata)
const currentMetadata = fileMetadata.get(activeTabId) as SkillFileMetadata | undefined
const nextMetadata = applyCredential(currentMetadata)
storeApi.getState().setDraftMetadata(activeTabId, nextMetadata)
storeApi.getState().pinTab(activeTabId)
}
@@ -535,10 +552,10 @@ const ToolBlockComponent = ({
currentTool={currentTool}
value={toolValue}
onChange={handleToolValueChange}
nodeId={toolBlockContext?.nodeId}
nodesOutputVars={toolBlockContext?.nodesOutputVars}
availableNodes={toolBlockContext?.availableNodes}
enableVariableReference={useModal}
nodeId={contextNodeId}
nodesOutputVars={nodesOutputVars}
availableNodes={availableNodes}
enableVariableReference={useModalValue}
/>
{readmeEntrance}
</div>
@@ -577,7 +594,7 @@ const ToolBlockComponent = ({
</span>
)}
</span>
{useModal && (
{useModalValue && (
<Modal
isShow={isSettingOpen}
onClose={() => setIsSettingOpen(false)}
@@ -589,7 +606,7 @@ const ToolBlockComponent = ({
</div>
</Modal>
)}
{!useModal && portalContainer && isSettingOpen && createPortal(
{!useModalValue && portalContainer && isSettingOpen && createPortal(
<div
className="absolute bottom-4 right-4 top-4 z-[99]"
data-tool-setting-panel="true"

View File

@@ -1,7 +1,10 @@
import type { ReactNode } from 'react'
import type { Node, NodeOutPutVar } from '@/app/components/workflow/types'
import { createContext, useContext } from 'react'
import { createContext, useCallback, useContext, useEffect, useRef } from 'react'
import { useStore } from 'zustand'
import { createStore } from 'zustand/vanilla'
type ToolBlockContextValue = {
export type ToolBlockContextValue = {
metadata?: Record<string, unknown>
onMetadataChange?: (metadata: Record<string, unknown>) => void
useModal?: boolean
@@ -10,8 +13,56 @@ type ToolBlockContextValue = {
availableNodes?: Node[]
}
const ToolBlockContext = createContext<ToolBlockContextValue | null>(null)
type ToolBlockStoreState = {
context: ToolBlockContextValue | null
setContext: (context: ToolBlockContextValue | null) => void
}
export const ToolBlockContextProvider = ToolBlockContext.Provider
const createToolBlockStore = (initialContext: ToolBlockContextValue | null) => createStore<ToolBlockStoreState>(set => ({
context: initialContext,
setContext: context => set({ context }),
}))
export const useToolBlockContext = () => useContext(ToolBlockContext)
type ToolBlockStore = ReturnType<typeof createToolBlockStore>
const defaultToolBlockStore = createToolBlockStore(null)
const ToolBlockStoreContext = createContext<ToolBlockStore | null>(null)
type ToolBlockContextProviderProps = {
value?: ToolBlockContextValue | null
children: ReactNode
}
export const ToolBlockContextProvider = ({ value, children }: ToolBlockContextProviderProps) => {
const storeRef = useRef<ToolBlockStore>(null)
if (!storeRef.current)
storeRef.current = createToolBlockStore(value ?? null)
useEffect(() => {
storeRef.current?.getState().setContext(value ?? null)
}, [value])
return (
<ToolBlockStoreContext.Provider value={storeRef.current}>
{children}
</ToolBlockStoreContext.Provider>
)
}
// eslint-disable-next-line react-refresh/only-export-components
export const useToolBlockContext = <T = ToolBlockContextValue | null,>(
selector?: (context: ToolBlockContextValue | null) => T,
) => {
const store = useContext(ToolBlockStoreContext) ?? defaultToolBlockStore
const selectContext = useCallback(
(state: ToolBlockStoreState) => {
if (selector)
return selector(state.context)
return state.context as T
},
[selector],
)
return useStore(store, selectContext)
}

View File

@@ -9,6 +9,7 @@ import * as React from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { createPortal } from 'react-dom'
import { useTranslation } from 'react-i18next'
import { useShallow } from 'zustand/react/shallow'
import AppIcon from '@/app/components/base/app-icon'
import Modal from '@/app/components/base/modal'
import { useSelectOrDelete } from '@/app/components/base/prompt-editor/hooks'
@@ -112,9 +113,25 @@ const ToolGroupBlockComponent = ({
const authBadgeLabel = t('skillEditor.authorizationBadge', { ns: 'workflow' })
const language = useGetLanguage()
const { theme } = useTheme()
const toolBlockContext = useToolBlockContext()
const isUsingExternalMetadata = Boolean(toolBlockContext?.onMetadataChange)
const useModal = Boolean(toolBlockContext?.useModal)
const {
metadata,
onMetadataChange,
useModal,
nodeId: contextNodeId,
nodesOutputVars,
availableNodes,
} = useToolBlockContext(
useShallow(context => ({
metadata: context?.metadata,
onMetadataChange: context?.onMetadataChange,
useModal: context?.useModal,
nodeId: context?.nodeId,
nodesOutputVars: context?.nodesOutputVars,
availableNodes: context?.availableNodes,
})),
)
const isUsingExternalMetadata = Boolean(onMetadataChange)
const useModalValue = Boolean(useModal)
const isInteractive = editor.isEditable()
const [isSettingOpen, setIsSettingOpen] = useState(false)
const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(null)
@@ -196,22 +213,22 @@ const ToolGroupBlockComponent = ({
if (!activeToolItem)
return undefined
if (isUsingExternalMetadata) {
const metadata = toolBlockContext?.metadata as SkillFileMetadata | undefined
return metadata?.tools?.[activeToolItem.configId]
const externalMetadata = metadata as SkillFileMetadata | undefined
return externalMetadata?.tools?.[activeToolItem.configId]
}
if (!activeTabId)
return undefined
const metadata = fileMetadata.get(activeTabId) as SkillFileMetadata | undefined
return metadata?.tools?.[activeToolItem.configId]
}, [activeTabId, activeToolItem, fileMetadata, isUsingExternalMetadata, toolBlockContext?.metadata])
const resultMetadata = fileMetadata.get(activeTabId) as SkillFileMetadata | undefined
return resultMetadata?.tools?.[activeToolItem.configId]
}, [activeTabId, activeToolItem, fileMetadata, isUsingExternalMetadata, metadata])
const metadataTools = useMemo(() => {
if (isUsingExternalMetadata)
return ((toolBlockContext?.metadata as SkillFileMetadata | undefined)?.tools || {}) as Record<string, ToolConfigMetadata>
return ((metadata as SkillFileMetadata | undefined)?.tools || {}) as Record<string, ToolConfigMetadata>
if (!activeTabId || activeTabId === START_TAB_ID)
return {}
return ((fileMetadata.get(activeTabId) as SkillFileMetadata | undefined)?.tools || {}) as Record<string, ToolConfigMetadata>
}, [activeTabId, fileMetadata, isUsingExternalMetadata, toolBlockContext?.metadata])
}, [activeTabId, fileMetadata, isUsingExternalMetadata, metadata])
const getVarKindType = (type: FormTypeEnum | string) => {
if (type === FormTypeEnum.file || type === FormTypeEnum.files)
@@ -348,7 +365,7 @@ const ToolGroupBlockComponent = ({
}, [configuredToolValue, isSettingOpen])
useEffect(() => {
if (useModal)
if (useModalValue)
return
const containerFromRef = ref.current?.closest('[data-skill-editor-root="true"]') as HTMLElement | null
const fallbackContainer = document.querySelector('[data-skill-editor-root="true"]') as HTMLElement | null
@@ -356,10 +373,10 @@ const ToolGroupBlockComponent = ({
if (container)
// eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect
setPortalContainer(container)
}, [ref, useModal])
}, [ref, useModalValue])
useEffect(() => {
if (!isSettingOpen || useModal)
if (!isSettingOpen || useModalValue)
return
const handleClickOutside = (event: MouseEvent) => {
@@ -384,7 +401,7 @@ const ToolGroupBlockComponent = ({
document.addEventListener('mousedown', handleClickOutside)
return () => document.removeEventListener('mousedown', handleClickOutside)
}, [isSettingOpen, portalContainer, ref, useModal])
}, [isSettingOpen, portalContainer, ref, useModalValue])
const resolvedEnabledByConfigId = useMemo(() => {
const next = { ...enabledByConfigId }
@@ -413,9 +430,9 @@ const ToolGroupBlockComponent = ({
setToolValue(nextValue)
const credentialId = normalizeCredentialId(nextValue.credential_id)
if (isUsingExternalMetadata) {
const metadata = (toolBlockContext?.metadata || {}) as SkillFileMetadata
const externalMetadata = (metadata || {}) as SkillFileMetadata
const toolType = currentProvider.type === CollectionType.mcp ? 'mcp' : 'builtin'
const currentToolMetadata = (metadata.tools || {})[activeToolItem.configId]
const currentToolMetadata = (externalMetadata.tools || {})[activeToolItem.configId]
const buildFields = (value: Record<string, unknown> | undefined) => {
if (!value)
return []
@@ -431,9 +448,9 @@ const ToolGroupBlockComponent = ({
...buildFields(nextValue.parameters),
]
const nextMetadata: SkillFileMetadata = {
...metadata,
...externalMetadata,
tools: {
...(metadata.tools || {}),
...(externalMetadata.tools || {}),
[activeToolItem.configId]: {
type: toolType,
configuration: { fields },
@@ -442,14 +459,14 @@ const ToolGroupBlockComponent = ({
},
},
}
toolBlockContext?.onMetadataChange?.(nextMetadata)
onMetadataChange?.(nextMetadata)
return
}
if (!activeTabId || activeTabId === START_TAB_ID)
return
const metadata = (fileMetadata.get(activeTabId) || {}) as SkillFileMetadata
const currentMetaData = (fileMetadata.get(activeTabId) || {}) as SkillFileMetadata
const toolType = currentProvider.type === CollectionType.mcp ? 'mcp' : 'builtin'
const currentToolMetadata = (metadata.tools || {})[activeToolItem.configId]
const currentToolMetadata = (currentMetaData.tools || {})[activeToolItem.configId]
const buildFields = (value: Record<string, unknown> | undefined) => {
if (!value)
return []
@@ -465,9 +482,9 @@ const ToolGroupBlockComponent = ({
...buildFields(nextValue.parameters),
]
const nextMetadata: SkillFileMetadata = {
...metadata,
...currentMetaData,
tools: {
...(metadata.tools || {}),
...(currentMetaData.tools || {}),
[activeToolItem.configId]: {
type: toolType,
configuration: { fields },
@@ -502,16 +519,16 @@ const ToolGroupBlockComponent = ({
return nextMetadata
}
if (isUsingExternalMetadata) {
toolBlockContext?.onMetadataChange?.(applyEnabled(toolBlockContext?.metadata as SkillFileMetadata | undefined))
onMetadataChange?.(applyEnabled(metadata as SkillFileMetadata | undefined))
return
}
if (!activeTabId || activeTabId === START_TAB_ID)
return
const metadata = fileMetadata.get(activeTabId) as SkillFileMetadata | undefined
const nextMetadata = applyEnabled(metadata)
const currentMetadata = fileMetadata.get(activeTabId) as SkillFileMetadata | undefined
const nextMetadata = applyEnabled(currentMetadata)
storeApi.getState().setDraftMetadata(activeTabId, nextMetadata)
storeApi.getState().pinTab(activeTabId)
}, [activeTabId, currentProvider?.type, fileMetadata, isUsingExternalMetadata, storeApi, toolBlockContext])
}, [activeTabId, currentProvider?.type, fileMetadata, isUsingExternalMetadata, metadata, onMetadataChange, storeApi])
const renderIcon = () => {
if (!resolvedIcon)
@@ -611,10 +628,10 @@ const ToolGroupBlockComponent = ({
currentTool={currentTool}
value={toolValue}
onChange={handleToolValueChange}
nodeId={toolBlockContext?.nodeId}
nodesOutputVars={toolBlockContext?.nodesOutputVars}
availableNodes={toolBlockContext?.availableNodes}
enableVariableReference={useModal}
nodeId={contextNodeId}
nodesOutputVars={nodesOutputVars}
availableNodes={availableNodes}
enableVariableReference={useModalValue}
/>
</div>
)
@@ -724,13 +741,13 @@ const ToolGroupBlockComponent = ({
return nextMetadata
}
if (isUsingExternalMetadata) {
toolBlockContext?.onMetadataChange?.(applyCredential(toolBlockContext?.metadata as SkillFileMetadata | undefined))
onMetadataChange?.(applyCredential(metadata as SkillFileMetadata | undefined))
return
}
if (!activeTabId || activeTabId === START_TAB_ID)
return
const metadata = fileMetadata.get(activeTabId) as SkillFileMetadata | undefined
const nextMetadata = applyCredential(metadata)
const currentMetadata = fileMetadata.get(activeTabId) as SkillFileMetadata | undefined
const nextMetadata = applyCredential(currentMetadata)
storeApi.getState().setDraftMetadata(activeTabId, nextMetadata)
storeApi.getState().pinTab(activeTabId)
}}
@@ -841,7 +858,7 @@ const ToolGroupBlockComponent = ({
</span>
)}
</span>
{useModal && (
{useModalValue && (
<Modal
isShow={isSettingOpen}
onClose={() => {
@@ -856,7 +873,7 @@ const ToolGroupBlockComponent = ({
</div>
</Modal>
)}
{!useModal && portalContainer && isSettingOpen && createPortal(
{!useModalValue && portalContainer && isSettingOpen && createPortal(
<div
className="absolute bottom-4 right-4 top-4 z-[99]"
data-tool-group-setting-panel="true"

View File

@@ -13,6 +13,7 @@ import * as React from 'react'
import { useCallback, useMemo, useState } from 'react'
import ReactDOM from 'react-dom'
import { v4 as uuid } from 'uuid'
import { useShallow } from 'zustand/react/shallow'
import { useBasicTypeaheadTriggerMatch } from '@/app/components/base/prompt-editor/hooks'
import { $splitNodeContainingQuery } from '@/app/components/base/prompt-editor/utils'
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
@@ -42,8 +43,13 @@ const ToolPickerBlock = ({ scope = 'all', enableAutoDefault = false }: ToolPicke
maxLength: 75,
})
const storeApi = useWorkflowStore()
const toolBlockContext = useToolBlockContext()
const isUsingExternalMetadata = Boolean(toolBlockContext?.onMetadataChange)
const { metadata, onMetadataChange } = useToolBlockContext(
useShallow(context => ({
metadata: context?.metadata,
onMetadataChange: context?.onMetadataChange,
})),
)
const isUsingExternalMetadata = Boolean(onMetadataChange)
const [queryString, setQueryString] = useState('')
const canUseAutoByType = useCallback(
@@ -133,21 +139,21 @@ const ToolPickerBlock = ({ scope = 'all', enableAutoDefault = false }: ToolPicke
})
if (isUsingExternalMetadata) {
const metadata = (toolBlockContext?.metadata || {}) as Record<string, unknown>
const nextMetadata = buildNextMetadata(metadata, toolEntries)
toolBlockContext?.onMetadataChange?.(nextMetadata)
const externalMetadata = (metadata || {}) as Record<string, unknown>
const nextMetadata = buildNextMetadata(externalMetadata, toolEntries)
onMetadataChange?.(nextMetadata)
return
}
const { activeTabId, fileMetadata, setDraftMetadata, pinTab } = storeApi.getState()
if (!activeTabId || activeTabId === START_TAB_ID)
return
const metadata = (fileMetadata.get(activeTabId) || {}) as Record<string, unknown>
const nextMetadata = buildNextMetadata(metadata, toolEntries)
const currentMetadata = (fileMetadata.get(activeTabId) || {}) as Record<string, unknown>
const nextMetadata = buildNextMetadata(currentMetadata, toolEntries)
setDraftMetadata(activeTabId, {
...nextMetadata,
})
pinTab(activeTabId)
}, [buildNextMetadata, editor, getMatchFromSelection, isUsingExternalMetadata, storeApi, toolBlockContext])
}, [buildNextMetadata, editor, getMatchFromSelection, isUsingExternalMetadata, metadata, onMetadataChange, storeApi])
const renderMenu = useCallback((
anchorElementRef: React.RefObject<HTMLElement | null>,