From fa1bc7f784a20f40f44d28f3136157afcc650c0d Mon Sep 17 00:00:00 2001 From: ljs Date: Thu, 8 Aug 2024 20:21:21 +0800 Subject: [PATCH] feat: select tool --- web/ui/src/modules/agent/agent-model.ts | 31 +++++ web/ui/src/modules/agent/module.ts | 3 +- .../components/ConfigList/ToolModal/index.tsx | 101 ++++++-------- .../components/ConfigList/index.tsx | 130 ++++++++++++------ .../components/ItemCard/index.less | 16 +++ .../components/ItemCard/index.tsx | 20 ++- 6 files changed, 193 insertions(+), 108 deletions(-) diff --git a/web/ui/src/modules/agent/agent-model.ts b/web/ui/src/modules/agent/agent-model.ts index 753934c..4461f24 100644 --- a/web/ui/src/modules/agent/agent-model.ts +++ b/web/ui/src/modules/agent/agent-model.ts @@ -2,6 +2,8 @@ import { Deferred, inject, prop, transient } from '@difizen/mana-app'; import { AsyncModel } from '../../common/async-model.js'; import { AxiosClient } from '../axios-client/index.js'; +import type { ToolModel } from '../tool/index.js'; +import { ToolManager } from '../tool/index.js'; import { AgentConfigManager } from './agent-config-manager.js'; import type { AgentConfig } from './agent-config.js'; @@ -71,6 +73,35 @@ export class AgentModel extends AsyncModel { @prop() tool: ToolMeta[]; + @inject(ToolManager) toolManager: ToolManager; + + @prop() + toolList: ToolModel[] = []; + + @prop() + toolListLoading = false; + + @prop() + selectedKnowledgeList: ToolModel[] = []; + + async updateToolList() { + try { + this.toolListLoading = true; + const options = await this.toolManager.getTools(); + this.toolList = options.map(this.toolManager.getOrCreateTool); + } finally { + this.toolListLoading = false; + } + } + + updateSelectedToolList(ids: React.Key[]) { + this.tool = this.toolList.filter((item) => ids.includes(item.id)); + } + + removeSelectedToolList(ids: React.Key[]) { + this.tool = this.tool.filter((item) => !ids.includes(item.id)); + } + // protected draftDeferred = new Deferred(); // get draftReady() { diff --git a/web/ui/src/modules/agent/module.ts b/web/ui/src/modules/agent/module.ts index cd175dd..03395a0 100644 --- a/web/ui/src/modules/agent/module.ts +++ b/web/ui/src/modules/agent/module.ts @@ -1,5 +1,7 @@ import { ManaModule } from '@difizen/mana-app'; +import { ToolManager, ToolModel } from '../tool/index.js'; + import { AgentConfigManager } from './agent-config-manager.js'; import { AgentConfig } from './agent-config.js'; import { AgentManager } from './agent-manager.js'; @@ -18,7 +20,6 @@ export const AgentBotModule = ManaModule.create().register( AgentConfig, AgentConfigManager, AgentMarket, - { token: AgentConfigFactory, useFactory: (ctx) => { diff --git a/web/ui/src/views/agent-config/components/ConfigList/ToolModal/index.tsx b/web/ui/src/views/agent-config/components/ConfigList/ToolModal/index.tsx index 156a55f..0c44cfb 100644 --- a/web/ui/src/views/agent-config/components/ConfigList/ToolModal/index.tsx +++ b/web/ui/src/views/agent-config/components/ConfigList/ToolModal/index.tsx @@ -1,89 +1,71 @@ +import { useInject, useMount, ViewInstance } from '@difizen/mana-app'; import type { TableColumnsType } from 'antd'; -import { Modal, Table } from 'antd'; -import { useState } from 'react'; +import { Avatar, Modal, Table } from 'antd'; +import type { TableRowSelection } from 'antd/es/table/interface.js'; +import { useMemo, useState } from 'react'; + +import { AgentConfig } from '../../../../../modules/agent/agent-config.js'; +import { ToolIcon } from '../../../../tool/tool-icon.js'; +import type { AgentConfigView } from '../../../view.js'; interface DataType { - key: React.Key; id: string; nickname: string; - avatar: number; + avatar: string; description: string; - address: string; - added: boolean; + parameters: string[]; } export const ToolModal = ({ + dataSource, open, onCancel, + onOk, + loading, + selectedRowKeys = [], + setSelectedRowKeys, }: { open: boolean; + dataSource: DataType[]; onCancel: () => void; + onOk: (selectedRowKeys: React.Key[]) => void; + loading: boolean; + selectedRowKeys: React.Key[]; + setSelectedRowKeys: (selectedRowKeys: React.Key[]) => void; }) => { - function useToolTable() { - const dataSource = [ - { - id: '1', - nickname: '胡彦斌', - avatar: 32, - description: '西湖区湖底公园1号', - address: '西湖区湖底公园1号', - added: true, - }, - { - id: '2', - nickname: '胡彦斌', - avatar: 32, - description: '西湖区湖底公园1号', - address: '西湖区湖底公园1号', - added: true, - }, - ] as DataType[]; - - const columns: TableColumnsType = [ - { - title: 'nickname', - dataIndex: 'nickname', - key: 'nickname', - }, + const columns = useMemo(() => { + const c: TableColumnsType = [ { title: 'id', dataIndex: 'id', key: 'id', }, + { title: 'avatar', dataIndex: 'avatar', key: 'avatar', + render(value) { + return } />; + }, }, { - title: 'description', - dataIndex: 'description', - key: 'description', + title: 'nickname', + dataIndex: 'nickname', + key: 'nickname', }, + { title: 'description', dataIndex: 'description', key: 'description', }, - { - title: 'added', - dataIndex: 'added', - key: 'added', - render: (text: boolean) => { - return text ? '是' : '否'; - }, - }, ]; - return { - dataSource, - columns, - }; - } - - const { dataSource, columns } = useToolTable(); + return c; + }, []); - const [selectedRowKeys, setSelectedRowKeys] = useState([]); - const [loading, setLoading] = useState(false); + // const [selectedRowKeys, setSelectedRowKeys] = + // useState(defaultSelectedRowKeys); const onSelectChange = (newSelectedRowKeys: React.Key[]) => { setSelectedRowKeys(newSelectedRowKeys); @@ -94,13 +76,20 @@ export const ToolModal = ({ onChange: onSelectChange, }; - const hasSelected = selectedRowKeys.length > 0; - return ( - onCancel()}> + { + onOk(selectedRowKeys); + }} + onCancel={() => onCancel()} + loading={loading} + > rowSelection={rowSelection} - dataSource={dataSource} + dataSource={dataSource || []} columns={columns} rowKey={'id'} > diff --git a/web/ui/src/views/agent-config/components/ConfigList/index.tsx b/web/ui/src/views/agent-config/components/ConfigList/index.tsx index ae64f86..7ad971a 100644 --- a/web/ui/src/views/agent-config/components/ConfigList/index.tsx +++ b/web/ui/src/views/agent-config/components/ConfigList/index.tsx @@ -1,26 +1,38 @@ import './index.less'; import { PlusOutlined } from '@ant-design/icons'; -import { useInject, ViewInstance } from '@difizen/mana-app'; +import { useInject, useMount, ViewInstance } from '@difizen/mana-app'; import type { CollapseProps } from 'antd'; -import { Collapse, Space } from 'antd'; +import { Avatar, Collapse, Space } from 'antd'; import { useCallback, useMemo, useState } from 'react'; +import type { ToolMeta } from '../../../../modules/agent/protocol.js'; import type { AgentConfigView } from '../../view.js'; import { SkillItem } from '../ItemCard/index.js'; import { KnowledgeModal } from './KnowledgeModal/index.js'; +import { ToolModal } from './ToolModal/index.js'; const clsPrefix = 'config-list'; -type SkillAddKey = 'tool' | 'knowledge'; -type OpeningSpeechAddKey = 'openingSpeech' | 'knowledge'; -type AddKey = SkillAddKey | OpeningSpeechAddKey; +type SkillKey = 'tool' | 'knowledge'; +type OpeningSpeechKey = 'openingSpeech'; +type ServiceType = SkillKey | OpeningSpeechKey; -const SkillConfigCard = ({ onAdd }: { onAdd: (key: AddKey) => void }) => { +const SkillConfigCard = ({ + onAdd, + tools, + knowledge, + onDelete, +}: { + onAdd: (serviceType: ServiceType) => void; + onDelete: (serviceType: ServiceType, itemKey: string) => void; + tools: ToolMeta[]; + knowledge: any[]; +}) => { const items: CollapseProps['items'] = useMemo(() => { return [ { - key: 'knowledge' as AddKey, + key: 'knowledge' as ServiceType, label: '知识', extra: (
@@ -33,26 +45,25 @@ const SkillConfigCard = ({ onAdd }: { onAdd: (key: AddKey) => void }) => {
), children: ( - - } - title="title" - description="descriptiondescriptiondescription" - > + <> + {knowledge.map((item) => { + return ( + } + title="title" + description="descriptiondescriptiondescription" + > + ); + })} + ), style: { padding: 0, }, }, { - key: 'tool' as AddKey, + key: 'tool' as ServiceType, label: '工具', extra: (
@@ -65,26 +76,28 @@ const SkillConfigCard = ({ onAdd }: { onAdd: (key: AddKey) => void }) => {
), children: ( - - } - title="title" - description="descriptiondescriptiondescription" - > + <> + {tools.map((item) => { + return ( + { + onDelete('tool', item.id); + }} + key={item.id} + icon={} + title={item.nickname || '-'} + description={item.description || '-'} + > + ); + })} + ), style: { padding: 0, }, }, ]; - }, [onAdd]); + }, [knowledge, onAdd, onDelete, tools]); return (
@@ -102,28 +115,55 @@ const SkillConfigCard = ({ onAdd }: { onAdd: (key: AddKey) => void }) => { export const ConfigList = () => { const instance = useInject(ViewInstance); - const [openKnowledge, setOpenKnowledge] = useState(false); - const [curAddKey, setCurAddKey] = useState(undefined); + const [curServiceType, setCurServiceType] = useState( + undefined, + ); - const onAdd = useCallback((addKey: AddKey) => { - setCurAddKey(addKey); - if (addKey === 'knowledge') { - setOpenKnowledge(true); - } + useMount(() => { + instance.agent.updateToolList(); + }); + + const onAdd = useCallback((addKey: ServiceType) => { + setCurServiceType(addKey); }, []); return (
- + { + if (serviceType === 'tool') { + instance.agent.removeSelectedToolList([itemKey]); + } + }} + > { - setOpenKnowledge(false); + setCurServiceType(undefined); }} > + + { + setCurServiceType(undefined); + }} + dataSource={instance.agent.toolList} + onOk={() => { + setCurServiceType(undefined); + }} + loading={instance.agent.toolListLoading} + selectedRowKeys={instance.agent.tool.map((item) => item.id)} + setSelectedRowKeys={(keys) => { + instance.agent.updateSelectedToolList(keys); + }} + >
); }; diff --git a/web/ui/src/views/agent-config/components/ItemCard/index.less b/web/ui/src/views/agent-config/components/ItemCard/index.less index cc8b067..2b28341 100644 --- a/web/ui/src/views/agent-config/components/ItemCard/index.less +++ b/web/ui/src/views/agent-config/components/ItemCard/index.less @@ -44,4 +44,20 @@ cursor: pointer; } } + + .ellipsisW100 { + width: 270px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .ellipsis2Line { + /* stylelint-disable-next-line */ + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + text-overflow: ellipsis; + } } diff --git a/web/ui/src/views/agent-config/components/ItemCard/index.tsx b/web/ui/src/views/agent-config/components/ItemCard/index.tsx index d24563e..1e25f9d 100644 --- a/web/ui/src/views/agent-config/components/ItemCard/index.tsx +++ b/web/ui/src/views/agent-config/components/ItemCard/index.tsx @@ -1,7 +1,7 @@ +import { DeleteOutlined } from '@ant-design/icons'; import { Flex, Space } from 'antd'; import React, { useState } from 'react'; import './index.less'; -import { DeleteOutlined, DeleteTwoTone } from '@ant-design/icons'; const clsPrefix = 'skill-item'; @@ -26,10 +26,12 @@ export const SkillItem = ({ icon, title, description, + onDelete, }: { icon: React.ReactNode; title: string; description: string; + onDelete?: () => void; }) => { const [showAct, setShowAct] = useState(false); @@ -43,15 +45,21 @@ export const SkillItem = ({ >
{icon}
-
{title}
-
{description}
+
{title}
+
{description}
{showAct && ( - }> - }> - }> + { + onDelete?.(); + }} + /> + } + > )}