mirror of https://github.com/langgenius/dify.git
Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins
This commit is contained in:
commit
f42cfe8075
|
|
@ -1,3 +1,4 @@
|
|||
import type { ReactNode } from 'react'
|
||||
import React from 'react'
|
||||
import { Variable02 } from '../icons/src/vender/solid/development'
|
||||
import VerticalLine from './vertical-line'
|
||||
|
|
@ -5,19 +6,21 @@ import HorizontalLine from './horizontal-line'
|
|||
|
||||
type ListEmptyProps = {
|
||||
title?: string
|
||||
description?: React.ReactNode
|
||||
description?: ReactNode
|
||||
icon?: ReactNode
|
||||
}
|
||||
|
||||
const ListEmpty = ({
|
||||
title,
|
||||
description,
|
||||
icon,
|
||||
}: ListEmptyProps) => {
|
||||
return (
|
||||
<div className='flex w-[320px] p-4 flex-col items-start gap-2 rounded-[10px] bg-workflow-process-bg'>
|
||||
<div className='flex w-10 h-10 justify-center items-center gap-2 rounded-[10px]'>
|
||||
<div className='flex relative p-1 justify-center items-center gap-2 grow self-stretch rounded-[10px]
|
||||
border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg'>
|
||||
<Variable02 className='w-5 h-5 shrink-0 text-text-accent' />
|
||||
{icon || <Variable02 className='w-5 h-5 shrink-0 text-text-accent' />}
|
||||
<VerticalLine className='absolute -right-[1px] top-1/2 -translate-y-1/4'/>
|
||||
<VerticalLine className='absolute -left-[1px] top-1/2 -translate-y-1/4'/>
|
||||
<HorizontalLine className='absolute top-0 left-3/4 -translate-x-1/4 -translate-y-1/2'/>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type { FC } from 'react'
|
|||
import { memo } from 'react'
|
||||
import { BlockEnum } from './types'
|
||||
import {
|
||||
Agent,
|
||||
Answer,
|
||||
Assigner,
|
||||
Code,
|
||||
|
|
@ -53,8 +54,7 @@ const getIcon = (type: BlockEnum, className: string) => {
|
|||
[BlockEnum.ParameterExtractor]: <ParameterExtractor className={className} />,
|
||||
[BlockEnum.DocExtractor]: <DocsExtractor className={className} />,
|
||||
[BlockEnum.ListFilter]: <ListFilter className={className} />,
|
||||
// TODO: add icon for Agent
|
||||
[BlockEnum.Agent]: <VariableX className={className} />,
|
||||
[BlockEnum.Agent]: <Agent className={className} />,
|
||||
}[type]
|
||||
}
|
||||
const ICON_CONTAINER_BG_COLOR_MAP: Record<string, string> = {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export const AgentStrategySelector = (props: AgentStrategySelectorProps) => {
|
|||
}, [query, list.data])
|
||||
// TODO: should be replaced by real data
|
||||
const isExternalInstalled = true
|
||||
const { t } = useTranslation()
|
||||
return <PortalToFollowElem open={open} onOpenChange={setOpen} placement='bottom'>
|
||||
<PortalToFollowElemTrigger className='w-full'>
|
||||
<div className='py-2 pl-3 pr-2 flex items-center rounded-lg bg-components-input-bg-normal w-full hover:bg-state-base-hover-alt select-none' onClick={() => setOpen(o => !o)}>
|
||||
|
|
@ -64,7 +65,7 @@ export const AgentStrategySelector = (props: AgentStrategySelectorProps) => {
|
|||
<p
|
||||
className={classNames(value ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder', 'text-xs px-1')}
|
||||
>
|
||||
{value?.agent_strategy_name || 'Select agentic strategy'}
|
||||
{value?.agent_strategy_name || t('workflow.nodes.agent.strategy.selectTip')}
|
||||
</p>
|
||||
{value && <div className='ml-auto flex items-center gap-1'>
|
||||
<InstallPluginButton onClick={e => e.stopPropagation()} size={'small'} />
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { AgentStrategySelector } from './agent-strategy-selector'
|
|||
import Link from 'next/link'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
||||
import { Agent } from '@/app/components/base/icons/src/vender/workflow'
|
||||
|
||||
export type Strategy = {
|
||||
agent_strategy_provider_name: string
|
||||
|
|
@ -39,8 +40,8 @@ export const AgentStrategy = (props: AgentStrategyProps) => {
|
|||
fieldLabelClassName='uppercase'
|
||||
/>
|
||||
</div>
|
||||
// TODO: list empty need a icon
|
||||
: <ListEmpty
|
||||
icon={<Agent className='w-5 h-5 shrink-0 text-text-accent' />}
|
||||
title={t('workflow.nodes.agent.strategy.configureTip')}
|
||||
description={<div className='text-text-tertiary text-xs'>
|
||||
{t('workflow.nodes.agent.strategy.configureTipDesc')} <br />
|
||||
|
|
|
|||
|
|
@ -6,18 +6,26 @@ import ModelSelector from '@/app/components/header/account-setting/model-provide
|
|||
import { Group, GroupLabel } from '../_base/components/group'
|
||||
import { ToolIcon } from './components/tool-icon'
|
||||
import useConfig from './use-config'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
|
||||
const { inputs } = useConfig(props.id, props.data)
|
||||
const { t } = useTranslation()
|
||||
return <div className='mb-1 px-3 py-1 space-y-1'>
|
||||
{inputs.agent_strategy_name
|
||||
? <SettingItem label='Strategy' status='error' tooltip='ReAct is not installed'>
|
||||
? <SettingItem
|
||||
label={t('workflow.nodes.agent.strategy.shortLabel')}
|
||||
status='error'
|
||||
tooltip={t('workflow.nodes.agent.strategyNotInstallTooltip', {
|
||||
strategy: inputs.agent_strategy_name,
|
||||
})}
|
||||
>
|
||||
{inputs.agent_strategy_name}
|
||||
</SettingItem>
|
||||
: <SettingItem label='Agentic strategy Not Set' />}
|
||||
: <SettingItem label={t('workflow.nodes.agent.strategyNotSet')} />}
|
||||
<Group
|
||||
label={<GroupLabel className='mt-1'>
|
||||
Model
|
||||
{t('workflow.nodes.agent.model')}
|
||||
</GroupLabel>}
|
||||
>
|
||||
<ModelSelector
|
||||
|
|
@ -34,12 +42,22 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
|
|||
/>
|
||||
</Group>
|
||||
<Group label={<GroupLabel className='mt-1'>
|
||||
Toolbox
|
||||
{t('workflow.nodes.agent.toolbox')}
|
||||
</GroupLabel>}>
|
||||
<div className='grid grid-cols-10 gap-0.5'>
|
||||
<ToolIcon src='/logo/logo.png' />
|
||||
<ToolIcon src='/logo/logo.png' status='error' tooltip='Gmail Sender is not installed' />
|
||||
<ToolIcon src='/logo/logo.png' status='warning' tooltip='DuckDuckGo AI Search Not Authorized' />
|
||||
<ToolIcon
|
||||
src='/logo/logo.png'
|
||||
status='error'
|
||||
tooltip={t('workflow.nodes.agent.toolNotInstallTooltip', {
|
||||
tool: 'Gmail Sender',
|
||||
})} />
|
||||
<ToolIcon
|
||||
src='/logo/logo.png'
|
||||
status='warning'
|
||||
tooltip={t('workflow.nodes.agent.toolNotAuthorizedTooltip', {
|
||||
tool: 'DuckDuckGo AI Search',
|
||||
})} />
|
||||
</div>
|
||||
</Group>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import type { AgentNodeType } from './types'
|
|||
import Field from '../_base/components/field'
|
||||
import { InputNumber } from '@/app/components/base/input-number'
|
||||
import Slider from '@/app/components/base/slider'
|
||||
import useNodeCrud from '../_base/hooks/use-node-crud'
|
||||
import { AgentStrategy } from '../_base/components/agent-strategy'
|
||||
import useConfig from './use-config'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const mockSchema = [
|
||||
{
|
||||
|
|
@ -260,7 +261,8 @@ const mockSchema = [
|
|||
] as const
|
||||
|
||||
const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => {
|
||||
const { inputs, setInputs } = useNodeCrud(props.id, props.data)
|
||||
const { inputs, setInputs } = useConfig(props.id, props.data)
|
||||
const { t } = useTranslation()
|
||||
const [iter, setIter] = [inputs.max_iterations, (value: number) => {
|
||||
setInputs({
|
||||
...inputs,
|
||||
|
|
@ -268,7 +270,7 @@ const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => {
|
|||
})
|
||||
}]
|
||||
return <div className='space-y-2 my-2'>
|
||||
<Field title={'Strategy'} className='px-4' >
|
||||
<Field title={t('workflow.nodes.agent.strategy.label')} className='px-4' >
|
||||
<AgentStrategy
|
||||
strategy={inputs.agent_strategy_name ? {
|
||||
agent_strategy_provider_name: inputs.agent_strategy_provider_name!,
|
||||
|
|
@ -291,10 +293,10 @@ const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => {
|
|||
})}
|
||||
/>
|
||||
</Field>
|
||||
<Field title={'tools'} className='px-4'>
|
||||
<Field title={t('workflow.nodes.agent.tools')} className='px-4'>
|
||||
|
||||
</Field>
|
||||
<Field title={'max iterations'} tooltip={'max iter'} inline className='px-4'>
|
||||
<Field title={t('workflow.nodes.agent.maxIterations')} tooltip={'max iter'} inline className='px-4'>
|
||||
<div className='flex w-[200px] items-center gap-3'>
|
||||
<Slider value={iter} onChange={setIter} className='w-full' min={1} max={10} />
|
||||
<InputNumber
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ const useConfig = (id: string, payload: AgentNodeType) => {
|
|||
return {
|
||||
readOnly,
|
||||
inputs,
|
||||
setInputs,
|
||||
handleVarListChange,
|
||||
handleAddVariable,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ import format from '.'
|
|||
import { simpleIterationData } from './data'
|
||||
|
||||
describe('format api data to tracing panel data', () => {
|
||||
// test('result should have no nodes in iteration node', () => {
|
||||
// }
|
||||
test('result should have no nodes in iteration node', () => {
|
||||
expect(format(simpleIterationData.in as any).find(item => !!(item as any).execution_metadata?.iteration_id)).toBeUndefined()
|
||||
})
|
||||
test('iteration should put nodes in details', () => {
|
||||
expect(format(simpleIterationData.in as any)).toEqual(simpleIterationData.output)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ const format = (list: NodeTracing[]): NodeTracing[] => {
|
|||
.map((item) => {
|
||||
if (item.node_type === BlockEnum.Iteration) {
|
||||
const childrenNodes = list.filter(child => child.execution_metadata?.iteration_id === item.node_id)
|
||||
const error = childrenNodes.find(child => child.status === 'failed')
|
||||
if (error) {
|
||||
item.status = 'failed'
|
||||
item.error = error.error
|
||||
}
|
||||
return addChildrenToIterationNode(item, childrenNodes)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
import type { NodeTracing } from '@/types/workflow'
|
||||
|
||||
const format = (list: NodeTracing[]): NodeTracing[] => {
|
||||
return list
|
||||
}
|
||||
|
||||
export default format
|
||||
|
|
@ -699,8 +699,11 @@ const translation = {
|
|||
},
|
||||
agent: {
|
||||
strategy: {
|
||||
label: 'Agentic Strategy',
|
||||
shortLabel: 'Strategy',
|
||||
configureTip: 'Please configure agentic strategy.',
|
||||
configureTipDesc: 'After configuring the agentic strategy, this node will automatically load the remaining configurations. The strategy will affect the mechanism of multi-step tool reasoning. ',
|
||||
selectTip: 'Select agentic strategy',
|
||||
},
|
||||
learnMore: 'Learn more',
|
||||
pluginNotInstalled: 'This plugin is not installed',
|
||||
|
|
@ -710,6 +713,15 @@ const translation = {
|
|||
install: 'Install',
|
||||
installing: 'Installing',
|
||||
},
|
||||
model: 'model',
|
||||
toolbox: 'toolbox',
|
||||
strategyNotSet: 'Agentic strategy Not Set',
|
||||
tools: 'Tools',
|
||||
maxIterations: 'Max Iterations',
|
||||
modelNotInstallTooltip: 'This model is not installed',
|
||||
toolNotInstallTooltip: '{{tool}} is not installed',
|
||||
toolNotAuthorizedTooltip: '{{tool}} Not Authorized',
|
||||
strategyNotInstallTooltip: '{{strategy}} is not installed',
|
||||
},
|
||||
},
|
||||
tracing: {
|
||||
|
|
|
|||
|
|
@ -699,8 +699,11 @@ const translation = {
|
|||
},
|
||||
agent: {
|
||||
strategy: {
|
||||
label: 'Agent 策略',
|
||||
shortLabel: '策略',
|
||||
configureTip: '请配置 Agent 策略。',
|
||||
configureTipDesc: '配置完成后,此节点将自动加载剩余配置。策略将影响多步工具推理的机制。',
|
||||
selectTip: '选择 Agent 策略',
|
||||
},
|
||||
learnMore: '了解更多',
|
||||
pluginNotInstalled: '插件未安装',
|
||||
|
|
@ -710,6 +713,15 @@ const translation = {
|
|||
install: '安装',
|
||||
installing: '安装中',
|
||||
},
|
||||
model: '模型',
|
||||
toolbox: '工具箱',
|
||||
strategyNotSet: '代理策略未设置',
|
||||
tools: '工具',
|
||||
maxIterations: '最大迭代次数',
|
||||
modelNotInstallTooltip: '此模型未安装',
|
||||
toolNotInstallTooltip: '{{tool}} 未安装',
|
||||
toolNotAuthorizedTooltip: '{{tool}} 未授权',
|
||||
strategyNotInstallTooltip: '{{strategy}} 未安装',
|
||||
},
|
||||
},
|
||||
tracing: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue