diff --git a/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx b/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx index 5bd79a5cef..6e54b939c3 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx @@ -39,7 +39,12 @@ type FormProps< inputClassName?: string isShowDefaultValue?: boolean fieldMoreInfo?: (payload: CredentialFormSchema | CustomFormSchema) => ReactNode - customRenderField?: (formSchema: CustomFormSchema, props: FormProps) => ReactNode + customRenderField?: ( + formSchema: CustomFormSchema, + props: Omit, 'override' | 'customRenderField'> + ) => ReactNode + // If return falsy value, this field will fallback to default render + override?: [Array, (formSchema: CredentialFormSchema) => ReactNode] } function Form< @@ -60,6 +65,7 @@ function Form< isShowDefaultValue = false, fieldMoreInfo, customRenderField, + override, }: FormProps) { const language = useLanguage() const [changeKey, setChangeKey] = useState('') @@ -97,6 +103,15 @@ function Form< triggerClassName='ml-1 w-4 h-4' asChild={false} /> )) + if (override) { + const [overrideTypes, overrideRender] = override + if (overrideTypes.includes(formSchema.type as FormTypeEnum)) { + const node = overrideRender(formSchema as CredentialFormSchema) + if (node) + return node + } + } + if (formSchema.type === FormTypeEnum.textInput || formSchema.type === FormTypeEnum.secretInput || formSchema.type === FormTypeEnum.textNumber) { const { variable, label, placeholder, required, show_on, @@ -343,7 +358,6 @@ function Form< inputClassName, isShowDefaultValue, fieldMoreInfo, - customRenderField, }) } } diff --git a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx index 5da5c8ae7c..98564e6b16 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx @@ -39,7 +39,6 @@ function formatStrategy(input: StrategyPluginDetail[], getIcon: (i: string) => s return input.map((item) => { const res: ToolWithProvider = { id: item.provider, - // TODO: replace this author: item.declaration.identity.author, name: item.declaration.identity.name, description: item.declaration.identity.description as any, diff --git a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx index eaa63f3354..81474b0a03 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx @@ -35,6 +35,87 @@ type MultipleToolSelectorSchema = CustomSchema<'array[tools]'> type CustomField = MaxIterFormSchema | ToolSelectorSchema | MultipleToolSelectorSchema +const devMockForm = [{ + name: 'model', + label: { + en_US: 'Model', + zh_Hans: '模型', + pt_BR: 'Model', + ja_JP: 'Model', + }, + placeholder: null, + scope: 'tool-call&llm', + auto_generate: null, + template: null, + required: true, + default: null, + min: null, + max: null, + options: [], + type: 'model-selector', +}, +{ + name: 'tools', + label: { + en_US: 'Tools list', + zh_Hans: '工具列表', + pt_BR: 'Tools list', + ja_JP: 'Tools list', + }, + placeholder: null, + scope: null, + auto_generate: null, + template: null, + required: true, + default: null, + min: null, + max: null, + options: [], + type: 'array[tools]', +}, +{ + name: 'instruction', + label: { + en_US: 'Instruction', + zh_Hans: '指令', + pt_BR: 'Instruction', + ja_JP: 'Instruction', + }, + placeholder: null, + scope: null, + auto_generate: { + type: 'prompt_instruction', + }, + template: { + enabled: true, + }, + required: true, + default: null, + min: null, + max: null, + options: [], + type: 'string', +}, +{ + name: 'query', + label: { + en_US: 'Query', + zh_Hans: '查询', + pt_BR: 'Query', + ja_JP: 'Query', + }, + placeholder: null, + scope: null, + auto_generate: null, + template: null, + required: true, + default: null, + min: null, + max: null, + options: [], + type: 'string', +}] + export const AgentStrategy = (props: AgentStrategyProps) => { const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange } = props const { t } = useTranslation() @@ -84,7 +165,6 @@ export const AgentStrategy = (props: AgentStrategyProps) => { } } } - console.log(formSchema) return
{ @@ -93,18 +173,7 @@ export const AgentStrategy = (props: AgentStrategyProps) => { formSchemas={[ ...formSchema, - { - type: 'max-iter', - variable: 'max_iterations', - label: { - en_US: 'Max Iterations', - zh_Hans: '最大迭代次数', - }, - name: 'max iter', - required: true, - show_on: [], - default: '3', - } as MaxIterFormSchema, + ...devMockForm as any, ]} value={formValue} onChange={onFormValueChange} diff --git a/web/app/components/workflow/nodes/_base/components/variable/utils.ts b/web/app/components/workflow/nodes/_base/components/variable/utils.ts index 277a0fa287..7685c3e587 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/utils.ts +++ b/web/app/components/workflow/nodes/_base/components/variable/utils.ts @@ -32,6 +32,7 @@ import { } from '@/app/components/workflow/constants' import type { PromptItem } from '@/models/debug' import { VAR_REGEX } from '@/config' +import type { AgentNodeType } from '../../../agent/types' export const isSystemVar = (valueSelector: ValueSelector) => { return valueSelector[0] === 'sys' || valueSelector[1] === 'sys' @@ -316,7 +317,18 @@ const formatItem = ( } case BlockEnum.Agent: { - res.vars = [] + const payload = data as AgentNodeType + if (!payload.agent_parameters) { + res.vars = [] + break + } + res.vars = Object.keys(payload.agent_parameters).map((key) => { + return { + variable: key, + // TODO: is this correct? + type: payload.agent_parameters![key].type as unknown as VarType, + } + }) break } @@ -789,6 +801,14 @@ export const getNodeUsedVars = (node: Node): ValueSelector[] => { res = [(data as ListFilterNodeType).variable] break } + + case BlockEnum.Agent: { + const payload = data as AgentNodeType + const params = payload.agent_parameters || {} + const mixVars = matchNotSystemVars(Object.keys(params)?.filter(key => params[key].type === ToolVarType.mixed).map(key => params[key].value) as string[]) + const vars = Object.keys(params).filter(key => params[key].type === ToolVarType.variable).map(key => params[key].value as string) || [] + res = [...(mixVars as ValueSelector[]), ...(vars as any)] + } } return res || [] } diff --git a/web/app/components/workflow/nodes/agent/default.ts b/web/app/components/workflow/nodes/agent/default.ts index 979df87f49..c748379cef 100644 --- a/web/app/components/workflow/nodes/agent/default.ts +++ b/web/app/components/workflow/nodes/agent/default.ts @@ -15,7 +15,7 @@ const nodeDefault: NodeDefault = { ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS }, - checkValid(payload) { + checkValid(payload, t, moreDataForCheckValid) { let isValid = true let errorMessages = '' if (payload.type) { diff --git a/web/app/components/workflow/nodes/agent/node.tsx b/web/app/components/workflow/nodes/agent/node.tsx index fca34623ec..2a55566f58 100644 --- a/web/app/components/workflow/nodes/agent/node.tsx +++ b/web/app/components/workflow/nodes/agent/node.tsx @@ -1,16 +1,42 @@ -import type { FC } from 'react' +import { type FC, useMemo } from 'react' import type { NodeProps } from '../../types' import type { AgentNodeType } from './types' import { SettingItem } from '../_base/components/setting-item' import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector' import { Group, GroupLabel } from '../_base/components/group' +import type { ToolIconProps } from './components/tool-icon' import { ToolIcon } from './components/tool-icon' import useConfig from './use-config' import { useTranslation } from 'react-i18next' +import { useInstalledPluginList } from '@/service/use-plugins' const AgentNode: FC> = (props) => { - const { inputs } = useConfig(props.id, props.data) + const { inputs, currentStrategy } = useConfig(props.id, props.data) const { t } = useTranslation() + const pluginList = useInstalledPluginList() + // TODO: Implement models + const models = useMemo(() => { + const models = [] + // if selected, show in node + // if required and not selected, show empty selector + // if not required and not selected, show nothing + }, [currentStrategy, inputs.agent_parameters]) + + const tools = useMemo(() => { + const tools: Array = [] + currentStrategy?.parameters.forEach((param) => { + if (['array[tool]', 'tool'].includes(param.type)) { + const vari = inputs.agent_parameters?.[param.name] + if (!vari) return + if (Array.isArray(vari.value)) { + // TODO: Implement array of tools + } + else { + // TODO: Implement single tool + } + } + }) + }, [currentStrategy, inputs.agent_parameters]) return
{inputs.agent_strategy_name ? { + printNodeStructure(child, level + 1) + }) + } +} + function addTitle({ list, level, parallelNumRecord, }: { @@ -52,6 +62,7 @@ function addTitle({ // list => group by parallel_id(parallel tree). const format = (list: NodeTracing[], t: any): NodeTracing[] => { + // console.log(list) const result: NodeTracing[] = [...list] const parallelFirstNodeMap: Record = {} // list to tree by parent_parallel_start_node_id and parallel_start_node_id @@ -65,7 +76,7 @@ const format = (list: NodeTracing[], t: any): NodeTracing[] => { const isParallelStartNode = !parallelFirstNodeMap[parallel_id] if (isParallelStartNode) { - const selfNode = { ...node } + const selfNode = { ...node, parallelDetail: undefined } node.parallelDetail = { isParallelStartNode: true, children: [selfNode], @@ -86,6 +97,7 @@ const format = (list: NodeTracing[], t: any): NodeTracing[] => { if (parentParallelStartNode!.parallelDetail.children) parentParallelStartNode!.parallelDetail.children.push(node) } + return } // append to parallel start node @@ -112,6 +124,11 @@ const format = (list: NodeTracing[], t: any): NodeTracing[] => { return true }) + // print node structure for debug + filteredInParallelSubNodes.forEach((node) => { + printNodeStructure(node, 0) + }) + const parallelNumRecord: Record = { num: 0, }