From c25cc9d5897345967a203131a887a36d2ccff176 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 27 Aug 2024 13:17:19 +0800 Subject: [PATCH 01/78] chore(flow): initialize --- web/packages/magent-flow/.eslintrc.mjs | 3 + web/packages/magent-flow/.fatherrc.ts | 9 + web/packages/magent-flow/.gitignore | 1 + web/packages/magent-flow/.stylelintignore | 1 + web/packages/magent-flow/CHANGELOG.md | 402 ++++++++++++++++++ web/packages/magent-flow/README.md | 280 ++++++++++++ web/packages/magent-flow/babel.config.json | 20 + web/packages/magent-flow/jest.config.mjs | 6 + web/packages/magent-flow/package.json | 78 ++++ .../magent-flow/src/FormSchema/index.ts | 331 ++++++++++++++ web/packages/magent-flow/src/RefForm/index.md | 31 ++ .../magent-flow/src/RefForm/index.tsx | 292 +++++++++++++ .../magent-flow/src/SchemaConfigForm/index.md | 29 ++ .../src/SchemaConfigForm/index.tsx | 369 ++++++++++++++++ web/packages/magent-flow/src/common/icons.ts | 3 + .../AIBasic/CascaderInNode/index.tsx | 14 + .../AIBasic/CollapseWrapper/index.tsx | 30 ++ .../OutputVariable/index.tsx | 14 + .../AIBasic/PromptEditor/constants.tsx | 3 + .../components/AIBasic/PromptEditor/hooks.ts | 58 +++ .../components/AIBasic/PromptEditor/index.tsx | 127 ++++++ .../plugins/component-picker-block/hooks.tsx | 185 ++++++++ .../plugins/component-picker-block/index.tsx | 168 ++++++++ .../plugins/component-picker-block/menu.tsx | 33 ++ .../component-picker-block/prompt-option.tsx | 53 +++ .../variable-option.tsx | 61 +++ .../PromptEditor/plugins/custom-text/node.tsx | 53 +++ .../plugins/on-blur-or-focus-block.tsx | 53 +++ .../PromptEditor/plugins/placeholder.tsx | 26 ++ .../PromptEditor/plugins/update-block.tsx | 45 ++ .../plugins/variable-block/index.tsx | 46 ++ .../plugins/variable-value-block/index.tsx | 55 +++ .../plugins/variable-value-block/node.tsx | 65 +++ .../plugins/variable-value-block/utils.ts | 5 + .../components/AIBasic/PromptEditor/types.ts | 28 ++ .../components/AIBasic/PromptEditor/utils.ts | 260 +++++++++++ .../components/AIBasic/SelectInNode/index.tsx | 13 + .../src/components/CustomEdge/index.tsx | 61 +++ .../magent-flow/src/components/Flow/index.tsx | 168 ++++++++ .../magent-flow/src/components/Flow/keys.ts | 116 +++++ .../src/components/FlowController/index.tsx | 18 + .../src/components/FlowWithPanel/index.tsx | 242 +++++++++++ .../FlowWithPanel/nodeTemplate.yaml | 171 ++++++++ .../src/components/Node/AgentNode/index.tsx | 53 +++ .../src/components/Node/CommonNode/index.tsx | 34 ++ .../src/components/Node/EndNode/index.tsx | 34 ++ .../src/components/Node/IfElseNode/index.tsx | 76 ++++ .../components/Node/KnowledgeNode/index.tsx | 84 ++++ .../src/components/Node/LLMNode/index.tsx | 120 ++++++ .../Node/NodeWrapper/Header/index.tsx | 18 + .../Node/NodeWrapper/Status/index.tsx | 73 ++++ .../src/components/Node/NodeWrapper/index.tsx | 91 ++++ .../src/components/Node/StartNode/index.tsx | 34 ++ .../magent-flow/src/components/Node/index.tsx | 0 .../src/components/NodePanel/index.tsx | 70 +++ .../src/components/RefForm/index.md | 31 ++ .../src/components/ReferenceForm/index.tsx | 117 +++++ .../src/components/ReferenceSelect/index.tsx | 61 +++ .../src/components/VariableForm/index.tsx | 148 +++++++ .../magent-flow/src/constants/constant.ts | 96 +++++ .../magent-flow/src/context/event-emitter.tsx | 30 ++ web/packages/magent-flow/src/index.ts | 8 + .../magent-flow/src/interfaces/flow.ts | 108 +++++ .../magent-flow/src/spec/FormSchema/index.ts | 328 ++++++++++++++ .../src/spec/__snapshots__/node.test.ts.snap | 65 +++ .../magent-flow/src/spec/node.test.ts | 199 +++++++++ web/packages/magent-flow/src/spec/node.ts | 82 ++++ .../magent-flow/src/spec/test-jsonschema.json | 87 ++++ web/packages/magent-flow/src/spec/uuid.ts | 21 + .../magent-flow/src/stores/useFlowStore.ts | 324 ++++++++++++++ .../src/stores/useKnowledgeStore.ts | 19 + .../magent-flow/src/stores/useModelStore.ts | 33 ++ .../src/stores/useShortcutsStore.ts | 86 ++++ .../src/stores/useUndoRedoStore.ts | 101 +++++ web/packages/magent-flow/src/tailwind.css | 4 + web/packages/magent-flow/src/utils/basic.ts | 8 + web/packages/magent-flow/src/utils/index.tsx | 2 + .../magent-flow/src/utils/reactflowUtils.ts | 13 + .../magent-flow/src/utils/wrappedClass.ts | 4 + web/packages/magent-flow/tailwind.config.js | 7 + web/packages/magent-flow/tsconfig.json | 14 + 81 files changed, 6709 insertions(+) create mode 100644 web/packages/magent-flow/.eslintrc.mjs create mode 100644 web/packages/magent-flow/.fatherrc.ts create mode 100644 web/packages/magent-flow/.gitignore create mode 100644 web/packages/magent-flow/.stylelintignore create mode 100644 web/packages/magent-flow/CHANGELOG.md create mode 100644 web/packages/magent-flow/README.md create mode 100644 web/packages/magent-flow/babel.config.json create mode 100644 web/packages/magent-flow/jest.config.mjs create mode 100644 web/packages/magent-flow/package.json create mode 100644 web/packages/magent-flow/src/FormSchema/index.ts create mode 100644 web/packages/magent-flow/src/RefForm/index.md create mode 100644 web/packages/magent-flow/src/RefForm/index.tsx create mode 100644 web/packages/magent-flow/src/SchemaConfigForm/index.md create mode 100644 web/packages/magent-flow/src/SchemaConfigForm/index.tsx create mode 100644 web/packages/magent-flow/src/common/icons.ts create mode 100644 web/packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/CollapseWrapper/index.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/constants.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/menu.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/utils.ts create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/types.ts create mode 100644 web/packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts create mode 100644 web/packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx create mode 100644 web/packages/magent-flow/src/components/CustomEdge/index.tsx create mode 100644 web/packages/magent-flow/src/components/Flow/index.tsx create mode 100644 web/packages/magent-flow/src/components/Flow/keys.ts create mode 100644 web/packages/magent-flow/src/components/FlowController/index.tsx create mode 100644 web/packages/magent-flow/src/components/FlowWithPanel/index.tsx create mode 100644 web/packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml create mode 100644 web/packages/magent-flow/src/components/Node/AgentNode/index.tsx create mode 100644 web/packages/magent-flow/src/components/Node/CommonNode/index.tsx create mode 100644 web/packages/magent-flow/src/components/Node/EndNode/index.tsx create mode 100644 web/packages/magent-flow/src/components/Node/IfElseNode/index.tsx create mode 100644 web/packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx create mode 100644 web/packages/magent-flow/src/components/Node/LLMNode/index.tsx create mode 100644 web/packages/magent-flow/src/components/Node/NodeWrapper/Header/index.tsx create mode 100644 web/packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx create mode 100644 web/packages/magent-flow/src/components/Node/NodeWrapper/index.tsx create mode 100644 web/packages/magent-flow/src/components/Node/StartNode/index.tsx create mode 100644 web/packages/magent-flow/src/components/Node/index.tsx create mode 100644 web/packages/magent-flow/src/components/NodePanel/index.tsx create mode 100644 web/packages/magent-flow/src/components/RefForm/index.md create mode 100644 web/packages/magent-flow/src/components/ReferenceForm/index.tsx create mode 100644 web/packages/magent-flow/src/components/ReferenceSelect/index.tsx create mode 100644 web/packages/magent-flow/src/components/VariableForm/index.tsx create mode 100644 web/packages/magent-flow/src/constants/constant.ts create mode 100644 web/packages/magent-flow/src/context/event-emitter.tsx create mode 100644 web/packages/magent-flow/src/index.ts create mode 100644 web/packages/magent-flow/src/interfaces/flow.ts create mode 100644 web/packages/magent-flow/src/spec/FormSchema/index.ts create mode 100644 web/packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap create mode 100644 web/packages/magent-flow/src/spec/node.test.ts create mode 100644 web/packages/magent-flow/src/spec/node.ts create mode 100644 web/packages/magent-flow/src/spec/test-jsonschema.json create mode 100644 web/packages/magent-flow/src/spec/uuid.ts create mode 100644 web/packages/magent-flow/src/stores/useFlowStore.ts create mode 100644 web/packages/magent-flow/src/stores/useKnowledgeStore.ts create mode 100644 web/packages/magent-flow/src/stores/useModelStore.ts create mode 100644 web/packages/magent-flow/src/stores/useShortcutsStore.ts create mode 100644 web/packages/magent-flow/src/stores/useUndoRedoStore.ts create mode 100644 web/packages/magent-flow/src/tailwind.css create mode 100644 web/packages/magent-flow/src/utils/basic.ts create mode 100644 web/packages/magent-flow/src/utils/index.tsx create mode 100644 web/packages/magent-flow/src/utils/reactflowUtils.ts create mode 100644 web/packages/magent-flow/src/utils/wrappedClass.ts create mode 100644 web/packages/magent-flow/tailwind.config.js create mode 100644 web/packages/magent-flow/tsconfig.json diff --git a/web/packages/magent-flow/.eslintrc.mjs b/web/packages/magent-flow/.eslintrc.mjs new file mode 100644 index 0000000..ffd7daa --- /dev/null +++ b/web/packages/magent-flow/.eslintrc.mjs @@ -0,0 +1,3 @@ +module.exports = { + extends: require.resolve('../../.eslintrc.js'), +}; diff --git a/web/packages/magent-flow/.fatherrc.ts b/web/packages/magent-flow/.fatherrc.ts new file mode 100644 index 0000000..a24475c --- /dev/null +++ b/web/packages/magent-flow/.fatherrc.ts @@ -0,0 +1,9 @@ +import babelConfig from './babel.config.json'; +export default { + platform: 'browser', + esm: { + output: 'es', + }, + extraBabelPlugins: babelConfig.plugins, + extraBabelPresets: [['@babel/preset-typescript', { onlyRemoveTypeImports: true }]], +}; diff --git a/web/packages/magent-flow/.gitignore b/web/packages/magent-flow/.gitignore new file mode 100644 index 0000000..bc61e82 --- /dev/null +++ b/web/packages/magent-flow/.gitignore @@ -0,0 +1 @@ +tailwind.out.css diff --git a/web/packages/magent-flow/.stylelintignore b/web/packages/magent-flow/.stylelintignore new file mode 100644 index 0000000..bc61e82 --- /dev/null +++ b/web/packages/magent-flow/.stylelintignore @@ -0,0 +1 @@ +tailwind.out.css diff --git a/web/packages/magent-flow/CHANGELOG.md b/web/packages/magent-flow/CHANGELOG.md new file mode 100644 index 0000000..1ed2e86 --- /dev/null +++ b/web/packages/magent-flow/CHANGELOG.md @@ -0,0 +1,402 @@ +# @difizen/libro-core + +## 0.1.33 + +### Patch Changes + +- 4811299: fix dark theme style +- Updated dependencies [4811299] + - @difizen/libro-code-editor@0.1.33 + - @difizen/libro-common@0.1.33 + - @difizen/libro-shared-model@0.1.33 + - @difizen/libro-virtualized@0.1.33 + +## 0.1.32 + +### Patch Changes + +- 2d90b29: fix(core): add deprecated +- Updated dependencies [2d90b29] + - @difizen/libro-code-editor@0.1.32 + - @difizen/libro-common@0.1.32 + - @difizen/libro-shared-model@0.1.32 + - @difizen/libro-virtualized@0.1.32 + +## 0.1.31 + +### Patch Changes + +- 3a07805: use modelId for modelCache +- 5b23c6d: Jupyter: integrate jupyter-widgets +- Updated dependencies [3a07805] +- Updated dependencies [5b23c6d] + - @difizen/libro-code-editor@0.1.31 + - @difizen/libro-common@0.1.31 + - @difizen/libro-shared-model@0.1.31 + - @difizen/libro-virtualized@0.1.31 + +## 0.1.30 + +### Patch Changes + +- 3c95a2c: improve keybind panel style +- Updated dependencies [3c95a2c] + - @difizen/libro-code-editor@0.1.30 + - @difizen/libro-common@0.1.30 + - @difizen/libro-shared-model@0.1.30 + - @difizen/libro-virtualized@0.1.30 + +## 0.1.29 + +### Patch Changes + +- d81dd35: Prompt: Migrate libro_server to libro_ai +- d661508: Lab: open file after creation +- Updated dependencies [d81dd35] +- Updated dependencies [d661508] + - @difizen/libro-shared-model@0.1.29 + - @difizen/libro-code-editor@0.1.29 + - @difizen/libro-virtualized@0.1.29 + - @difizen/libro-common@0.1.29 + +## 0.1.28 + +### Patch Changes + +- cc94f1d: 1.refactor(jupyter): use ContentSaveContribution +- Updated dependencies [cc94f1d] + - @difizen/libro-code-editor@0.1.28 + - @difizen/libro-common@0.1.28 + - @difizen/libro-shared-model@0.1.28 + - @difizen/libro-virtualized@0.1.28 + +## 0.1.27 + +### Patch Changes + +- 5341bd6: feat: go to definition + feat: signature help +- Updated dependencies [5341bd6] + - @difizen/libro-code-editor@0.1.27 + - @difizen/libro-common@0.1.27 + - @difizen/libro-shared-model@0.1.27 + - @difizen/libro-virtualized@0.1.27 + +## 0.1.26 + +### Patch Changes + +- 6a520ad: fix: add import file extension +- Updated dependencies [6a520ad] + - @difizen/libro-code-editor@0.1.26 + - @difizen/libro-virtualized@0.1.26 + - @difizen/libro-common@0.1.26 + - @difizen/libro-shared-model@0.1.26 + +## 0.1.24 + +### Patch Changes + +- 1bcfbee: 1.fix: get correct url when create notebook file 2.chore: update the peerDependencies about react +- Updated dependencies [1bcfbee] + - @difizen/libro-code-editor@0.1.24 + - @difizen/libro-virtualized@0.1.24 + - @difizen/libro-common@0.1.24 + +## 0.1.23 + +### Patch Changes + +- e37f319: fix: remove useless code about format button +- Updated dependencies [e37f319] + - @difizen/libro-code-editor@0.1.23 + - @difizen/libro-common@0.1.23 + - @difizen/libro-shared-model@0.1.23 + - @difizen/libro-virtualized@0.1.23 + +## 0.1.22 + +### Patch Changes + +- 669e05b: fix: valid notebook + feat(jupyter): add restart kernel + fix: poll kernelSpec after serverManager ready +- Updated dependencies [669e05b] + - @difizen/libro-code-editor@0.1.22 + - @difizen/libro-common@0.1.22 + - @difizen/libro-shared-model@0.1.22 + - @difizen/libro-virtualized@0.1.22 + +## 0.1.21 + +### Patch Changes + +- 9da4081: 1.fix: search view hide not focus libro view +- Updated dependencies [9da4081] + - @difizen/libro-code-editor@0.1.21 + - @difizen/libro-common@0.1.21 + - @difizen/libro-shared-model@0.1.21 + - @difizen/libro-virtualized@0.1.21 + +## 0.1.20 + +### Patch Changes + +- f3924d3: 1.fix search scroll on large cell 2.add libroModel in VirtualizedManager +- Updated dependencies [f3924d3] + - @difizen/libro-code-editor@0.1.20 + - @difizen/libro-common@0.1.20 + - @difizen/libro-shared-model@0.1.20 + - @difizen/libro-virtualized@0.1.20 + +## 0.1.19 + +### Patch Changes + +- fe3ee51: fix:poll kernels when serverManager ready +- Updated dependencies [fe3ee51] + - @difizen/libro-code-editor@0.1.19 + - @difizen/libro-common@0.1.19 + - @difizen/libro-shared-model@0.1.19 + - @difizen/libro-virtualized@0.1.19 + +## 0.1.18 + +### Patch Changes + +- f7c6839: File uploads can now be triggered by right-clicking on the file tree. +- 0f9e69d: Lab supports saving of all code files. +- 0f9e69d: More user-friendly prompt cell setting operation. +- Updated dependencies [f7c6839] +- Updated dependencies [0f9e69d] +- Updated dependencies [0f9e69d] + - @difizen/libro-shared-model@0.1.18 + - @difizen/libro-code-editor@0.1.18 + - @difizen/libro-virtualized@0.1.18 + - @difizen/libro-common@0.1.18 + +## 0.1.17 + +### Patch Changes + +- b159277: insert and execute output in a cell +- 9ff1bf9: Support file download. +- Updated dependencies [b159277] +- Updated dependencies [9ff1bf9] + - @difizen/libro-code-editor@0.1.17 + - @difizen/libro-common@0.1.17 + - @difizen/libro-shared-model@0.1.17 + - @difizen/libro-virtualized@0.1.17 + +## 0.1.16 + +### Patch Changes + +- 7d1edf3: Fix: Make Terminals opened from left panel same as the one you created, instead of creating a new terminal view. +- 90f6f8e: Fix: Cancel observing outputs height change' +- Updated dependencies [7d1edf3] +- Updated dependencies [90f6f8e] + - @difizen/libro-code-editor@0.1.16 + - @difizen/libro-common@0.1.16 + - @difizen/libro-shared-model@0.1.16 + - @difizen/libro-virtualized@0.1.16 + +## 0.1.15 + +### Patch Changes + +- 1b88a16: Feature: Better Prompt cell! Now based on better prompt magic support, you can use prompt cells to chat directly with OpenAI models. And you can put chats in context and create exciting workflows. +- Updated dependencies [1b88a16] + - @difizen/libro-shared-model@0.1.15 + - @difizen/libro-code-editor@0.1.15 + - @difizen/libro-virtualized@0.1.15 + - @difizen/libro-common@0.1.15 + +## 0.1.14 + +### Patch Changes + +- 0b882d3: 1. prompt cell adapt to the api of libro-server 2.fix the editor in CodeEditorView is undefined +- Updated dependencies [0b882d3] + - @difizen/libro-code-editor@0.1.14 + - @difizen/libro-common@0.1.14 + - @difizen/libro-shared-model@0.1.14 + - @difizen/libro-virtualized@0.1.14 + +## 0.1.13 + +### Patch Changes + +- 262ba79: 1. fix the editor in CodeEditorView is undefined +- Updated dependencies [262ba79] + - @difizen/libro-code-editor@0.1.13 + - @difizen/libro-common@0.1.13 + - @difizen/libro-shared-model@0.1.13 + - @difizen/libro-virtualized@0.1.13 + +## 0.1.12 + +### Patch Changes + +- bf45fa2: 1. fix:close the open tab when delete the file 2. stop propagation when focus cell right toolbar +- Updated dependencies [bf45fa2] + - @difizen/libro-code-editor@0.1.12 + - @difizen/libro-common@0.1.12 + - @difizen/libro-shared-model@0.1.12 + - @difizen/libro-virtualized@0.1.12 + +## 0.1.11 + +### Patch Changes + +- 236634d: 1.libro keybind not work when switching tabs + 2.auto focus when input file name. + 3.editor resize when CodeEditorViewer resize + 4.add file size warning + 5.add UI for file formats not supported for viewing + 6.file name error when select other format +- Updated dependencies [236634d] + - @difizen/libro-code-editor@0.1.11 + - @difizen/libro-common@0.1.11 + - @difizen/libro-shared-model@0.1.11 + - @difizen/libro-virtualized@0.1.11 + +## 0.1.10 + +### Patch Changes + +- ccdd12d: 1. add remove action in file tree menu +- Updated dependencies [ccdd12d] + - @difizen/libro-code-editor@0.1.10 + - @difizen/libro-common@0.1.10 + - @difizen/libro-shared-model@0.1.10 + - @difizen/libro-virtualized@0.1.10 + +## 0.1.9 + +### Patch Changes + +- ad803e2: 1. use codeEditorViewer as the last resort file viewer. 2. fix terminal +- Updated dependencies [ad803e2] + - @difizen/libro-code-editor@0.1.9 + - @difizen/libro-common@0.1.9 + - @difizen/libro-shared-model@0.1.9 + - @difizen/libro-virtualized@0.1.9 + +## 0.1.8 + +### Patch Changes + +- 1. Support json and other file formats. + 2. Dynamic shortcut keys and menus when switching tabs. +- Updated dependencies + - @difizen/libro-code-editor@0.1.8 + - @difizen/libro-common@0.1.8 + - @difizen/libro-shared-model@0.1.8 + - @difizen/libro-virtualized@0.1.8 + +## 0.1.7 + +### Patch Changes + +- Clean lab modules. +- Updated dependencies + - @difizen/libro-code-editor@0.1.7 + - @difizen/libro-common@0.1.7 + - @difizen/libro-shared-model@0.1.7 + - @difizen/libro-virtualized@0.1.7 + +## 0.1.6 + +### Patch Changes + +- Support code file editing. +- Updated dependencies + - @difizen/libro-code-editor@0.1.6 + - @difizen/libro-common@0.1.6 + - @difizen/libro-shared-model@0.1.6 + - @difizen/libro-virtualized@0.1.6 + +## 0.1.5 + +### Patch Changes + +- 1. Support image preview. + 2. Export the definition and implementation of the libro lab module. +- Updated dependencies + - @difizen/libro-code-editor@0.1.5 + - @difizen/libro-common@0.1.5 + - @difizen/libro-shared-model@0.1.5 + - @difizen/libro-virtualized@0.1.5 + +## 0.1.4 + +### Patch Changes + +- Fix issues with lsp and virtual list. +- Updated dependencies + - @difizen/libro-code-editor@0.1.4 + - @difizen/libro-virtualized@0.1.4 + - @difizen/libro-common@0.1.4 + - @difizen/libro-shared-model@0.1.4 + +## 0.1.3 + +### Patch Changes + +- Fix the content format issue of prompt cell +- Updated dependencies + - @difizen/libro-code-editor@0.1.3 + - @difizen/libro-common@0.1.3 + - @difizen/libro-shared-model@0.1.3 + - @difizen/libro-virtualized@0.1.3 + +## 0.1.2 + +### Patch Changes + +- 1. Support monaco editor, code cell is migrated to monaco editor by default. + 2. Support virtual lists to improve performance. + 3. libro lab can now use terminal. +- Updated dependencies + - @difizen/libro-code-editor@0.1.2 + - @difizen/libro-common@0.1.2 + - @difizen/libro-shared-model@0.1.2 + - @difizen/libro-virtualized@0.1.2 + +## 0.1.1 + +### Patch Changes + +- 1. Prompt cell is now available 🎉. + 2. Better lab UI. +- Updated dependencies + - @difizen/libro-code-editor@0.1.1 + - @difizen/libro-common@0.1.1 + - @difizen/libro-shared-model@0.1.1 + +## 0.1.0 + +### Minor Changes + +- 1. All modules used to support the notebook editor. + 2. Support lab products. + +### Patch Changes + +- 127cb35: Initia version +- Updated dependencies [127cb35] +- Updated dependencies + - @difizen/libro-code-editor@0.1.0 + - @difizen/libro-common@0.1.0 + - @difizen/libro-shared-model@0.1.0 + +## 0.0.2-alpha.0 + +### Patch Changes + +- Initia version +- Updated dependencies + - @difizen/libro-code-editor@0.0.2-alpha.0 + - @difizen/libro-common@0.0.2-alpha.0 + - @difizen/libro-shared-model@0.0.2-alpha.0 diff --git a/web/packages/magent-flow/README.md b/web/packages/magent-flow/README.md new file mode 100644 index 0000000..07ecaf3 --- /dev/null +++ b/web/packages/magent-flow/README.md @@ -0,0 +1,280 @@ +# libro-core + +## Token/API + +### LibroService + +LibroService 管理 libro 实例,libro view 创建、活跃 libro view 的监听等能力。 + +```typescript +// 组件内引入 +const service = useInject(LibroService); + +// 属性引入 +@inject(LibroService) service:LibroService; + +// 事件监听 +service.getOrCreateView(options); +service.onActiveChanged(callback); +service.onFocusChanged(callback); +service.onNotebookViewCreated(callback); +``` + +## 扩展点 + +### 单元格扩展 + +使用单元格扩展可以增加自定义的单元格类型,内置的单元格类型也均基于该扩展定义实现。 + +单元格定义分为 model 和 view 两部分,model 定义单元格的数据结构,view 定义单元格的渲染方式和提供交互能力。每种单元格都需要对创建时接收到的参数返回优先级,按照最高优先级的单元格类型创建单元格。 + +```typescript +export interface CellModelContribution { + cellMeta: CellMeta; + canHandle: (options: CellOptions, libroType?: string) => number; + createModel: (options: CellOptions) => MaybePromise; + getDefaultCellOption?: () => CellOptions; +} +export interface CellViewContribution { + canHandle: (options: CellOptions) => number; + view: Newable; +} +``` + +### 输出扩展 + +使用输出扩展可以增加自定义的输出类型,内置的输出类型也均基于该扩展定义实现。在 jupyter 场景下,用户一般不需要增加输出类型的扩展,而仅需要增加 mime 渲染器,mime 渲染器扩展由 output 实现。 + +```typescript +export interface OutputContribution { + canHandle: (output: IOutput) => number; + factory: OutputModelFactory; +} +``` + +### 内容加载扩展 + +用户有时候从自定义存储中读取 notebook 数据,可以通过内容加载扩展来实现,这里要求用户的返回数据符合 notebook 的数据结构。 + +```typescript +export interface ContentContribution { + canHandle: (options: Record, model: any) => number; + loadContent: (options: Record, model: any) => Promise; +} +``` + +### 视图插槽 + +如果希望在编辑器内部增加一些自定义的渲染像,除了可以覆盖内置的渲染器外,还可以通过视图插槽的方式来实现。 + +内置插槽位置如下: + +- container +- content +- list +- right + +```typescript +export interface LibroExtensionSlotContribution { + factory: LibroExtensionSlotFactory; + slot: LibroSlot; + viewOpenOption?: { + order?: string; + reveal?: boolean; + }; +} +``` + +## 命令 & 快捷键 + +### 文档命令 + +| 命令 | 快捷键 | 命令模式 | 说明 | +| ------------------ | ----------- | -------- | -------- | +| `document:save` | `ctrlcmd+s` | | 保存文档 | +| `document:setting` | | | 打开配置 | + +### kernel 命令 + +| 命令 | 快捷键 | 命令模式 | 说明 | +| ------------------------------ | ------ | -------- | ------------------- | +| `notebook:change-kernel` | | | Change Kernel | +| `notebook:get-kernel` | | | Get Kernel | +| `notebook:interrupt-kernel` | | | Interrupt Kernel | +| `notebook:reconnect-to-kernel` | | | Reconnect to Kernel | +| `notebook:restart-kernel` | | | Restart Kernel | +| `notebook:shutdown-kernel` | | | Shutdown Kernel | + +### notebook 命令 + +| 命令 | 快捷键 | 命令模式 | 说明 | +| ------------------------------------------------ | ---------------------- | -------- | ----------------------------------------------- | +| `notebook:interrupt` | | | Interrupt | +| `notebook:change-cell-to` | | | | +| `notebook:change-cell-to-code` | `Y` | ✓ | Change to Code Cell Type | +| `notebook:change-cell-to-heading-1` | `1` | ✓ | Change to Heading 1 | +| `notebook:change-cell-to-heading-2` | `2` | ✓ | Change to Heading 2 | +| `notebook:change-cell-to-heading-3` | `3` | ✓ | Change to Heading 3 | +| `notebook:change-cell-to-heading-4` | `4` | ✓ | Change to Heading 4 | +| `notebook:change-cell-to-heading-5` | `5` | ✓ | Change to Heading 5 | +| `notebook:change-cell-to-heading-6` | `6` | ✓ | Change to Heading 6 | +| `notebook:change-cell-to-markdown` | `M` | ✓ | Change to Markdown Cell Type | +| `notebook:change-cell-to-raw` | `R` | ✓ | Change to Raw Cell Type | +| `notebook:clear-all-cell-outputs` | | | Clear Outputs of All Cells | +| `notebook:clear-cell-outputs` | | | Clear Cell Output | +| `notebook:close-and-shutdown` | | | Close editor and shut down kernel | +| `notebook:collapse-all-headings` | `ctrlcmd+shift+left` | | Collapse All Headings | +| `notebook:copy-cell` | `C` | ✓ | Copy Cells | +| `notebook:cut-cell` | `X` | ✓ | Cut Cells | +| `notebook:delete-cell` | `D D` | ✓ | Delete Cells | +| `notebook:deselect-all` | | | Deselect All Cells | +| `notebook:disable-output-scrolling` | | | Disable Scrolling for Outputs | +| `notebook:duplicate-below` | | | Duplicate Cells Below | +| `notebook:enable-output-scrolling` | | | Enable Scrolling for Outputs | +| `notebook:enter-command-mode` | `esc` | | Enter Command Mode | +| `notebook:enter-edit-mode` | `enter` | | Enter Edit Mode | +| `notebook:expand-all-headings` | `ctrlcmd+shift+right` | | Expand All Headings | +| `notebook:export-to-format` | | | Save and Export Notebook to the given format | +| `notebook:extend-marked-cells-above` | `shift+up` `shift+K` | | Extend Selection Above | +| `notebook:extend-marked-cells-below` | `shift+down` `shift+J` | | Extend Selection Below | +| `notebook:extend-marked-cells-bottom` | `shift+end` | | Extend Selection to Bottom | +| `notebook:extend-marked-cells-top` | `shift+home` | | Extend Selection to Top | +| `notebook:hide-all-cell` | | | | +| `notebook:hide-all-cell-code` | | | Collapse All Code | +| `notebook:hide-all-cell-output` | | | Collapse All Outputs | +| `notebook:hide-cell-code` | | | Collapse Selected Code | +| `notebook:hide-or-show-cell-code` | `ctrlcmd+'` | | Hide or show Selected Code | +| `notebook:hide-cell-outputs` | | | Collapse Selected Outputs | +| `notebook:hide-or-show-outputs` | `ctrlcmd+o` | | Hide or show Selected outputs | +| `notebook:insert-cell-above` | `A` | ✓ | Insert Cell Above | +| `notebook:insert-cell-below` | `B` | ✓ | Insert Cell Below | +| `notebook:insert-heading-above` | `shift+A` | ✓ | Insert Heading Above Current Heading | +| `notebook:insert-heading-below` | `shift+B` | ✓ | Insert Heading Below Current Heading | +| `notebook:merge-cell-above` | `ctrlcmd+backspace` | ✓ | Merge Cell Above | +| `notebook:merge-cell-below` | `ctrlcmd+shift+M` | ✓ | Merge Cell Below | +| `notebook:merge-cells` | `shift+M` | ✓ | Merge Selected Cells | +| `notebook:move-cell-down` | `ctrlcmd+shift+down` | ✓ | Move Cells Down | +| `notebook:move-cell-up` | `ctrlcmd+shift+up` | ✓ | Move Cells Up | +| `notebook:move-cursor-down` | `down` `J` | ✓ | Select Cell Below | +| `notebook:move-cursor-up` | `up` `K` | ✓ | Select Cell Up | +| `notebook:move-cursor-heading-above-or-collapse` | `left` | ✓ | Select Heading Above or Collapse Heading | +| `notebook:move-cursor-heading-below-or-expand` | `right` | ✓ | Select Heading Below or Collapse Heading | +| `notebook:paste-and-replace-cell` | | | Paste Cells and Replace | +| `notebook:paste-cell-above` | | | Paste Cells Above | +| `notebook:paste-cell-below` | `V` | ✓ | Paste Cells Below | +| `notebook:redo` | | | Redo | +| `notebook:redo-cell-action` | `shift+Z` | ✓ | Redo Cell Operation | +| `notebook:render-all-markdown` | | | Render All Markdown Cells | +| `notebook:replace-selection` | | | Replace Selection in Notebook Cell | +| `notebook:restart-and-run-to-selected` | | | Restart and Run up to Selected Cell | +| `notebook:restart-clear-output` | | | Restart and Clear Outputs of All Cells | +| `notebook:restart-run-all` | | | Restart and Run All Cells | +| `notebook:run-all-above` | | | Run All Above Selected Cell | +| `notebook:run-all-below` | | | Run All Below Selected Cell | +| `notebook:run-all-cells` | | | Run All Cells | +| `notebook:run-cell` | `ctrlcmd+enter` | | Run Selected Cells and Don't Advance | +| `notebook:run-cell-and-insert-below` | `alt+enter` | | Run Selected Cells and Insert Below | +| `notebook:run-cell-and-select-next` | `shift+enter` | | Run Selected Cells and Select Below | +| `notebook:run-in-console` | | | Run Selected Text or Current Line in Console | +| `notebook:select-all` | `ctrlcmd+A` | ✓ | Select All Cells | +| `notebook:select-last-run-cell` | | | Select current running or last run cell | +| `notebook:set-side-by-side-ratio` | | | Set Side by Side Ratio | +| `notebook:show-all-cell` | | | Expand All Cell | +| `notebook:show-all-cell-code` | | | Expand All Code | +| `notebook:show-all-cell-outputs` | | | Expand All Outputs | +| `notebook:show-cell-code` | | | Expand Selected Code | +| `notebook:show-cell-outputs` | | | Expand Selected Outputs | +| `notebook:split-cell-at-cursor` | `ctrlcmd+shift+-` | | Split Cell | +| `notebook:toggle-all-cell-line-numbers` | `shift+L` | | Show Line Numbers | +| `notebook:toggle-autoclosing-brackets` | | | Auto Close Brackets for All Notebook Cell Types | +| `notebook:toggle-heading-collapse` | | | Toggle Collapse Notebook Heading | +| `notebook:toggle-render-side-by-side-current` | `shift+R` | ✓ | Render Side-by-Side | +| `notebook:trust` | | | Trust Notebook | +| `notebook:undo` | | | Undo | +| `notebook:undo-cell-action` | `Z` | ✓ | Undo Cell Operation | +| `notebook:insert-cell-bottom` | | | | + +## 配置 & 主题 + +libro 内置了一些配置项和主题设置,用户可以是用 mana 的配置模块和主题模块来消费或变更。 + +| 配置项 | 说明 | 默认值 | +| ----------------------------------------------- | --------------------------------------- | ------- | +| `libro.header.toolbar` | 是否显示 libro 顶部工具栏 | `true` | +| `libro.cell.top-toolbar` | 是否显示单元格顶部工具栏 | `true` | +| `libro.cell.side-toolbar` | 是否显示单元格侧边工具栏 | `true` | +| `libro.command.insert-cell-below` | 没有单元格时是否默认创建单元格 | `true` | +| `libro.command.enter-edit-mode-when-add-cell` | 增加单元格操作默认进入编辑态 | `true` | +| `libro.command.collapser-active` | 点击左侧长条是否可以隐藏与显示单元格 | `true` | +| `libro.command.multiselection-when-shift-click` | 按住 shift 键并点击拖拽区域可以进行多选 | `true` | +| `libro.right.content.fixed` | libro view 的右边栏是否相对固定 | `false` | + +| 颜色 | css 变量 | 暗色主题 | 亮色主题 | 高对比主题 | 说明 | +| -------------------------------------------- | -------- | ----------- | ----------- | ---------- | ---- | +| `libro.warning.background` | | `#A9611466` | `#FFFBE6` | | | +| `libro.drag.hover.line.color` | | `#467DB0` | `#BFE0FF` | | | +| `libro.background` | | `#1F2022` | `#FFFFFF` | | | +| `libro.popover.background.color` | | `#2F3032` | `#FFFFFF` | | | +| `libro.menu.hover.color` | | `#515359` | `#EBF6FF` | | | +| `libro.dropdown.icon.color` | | `#FFFFFF4D` | `#00000033` | | | +| `libro.input.background` | | `#19191B` | `#F4F6FB` | | | +| `libro.text.default.color` | | `#E3E4E6` | `#000000` | | | +| `libro.text.tertiary.color` | | `#BDC0C4` | `#B8BABA` | | | +| `libro.output.background` | | `#292A2D` | `#FFFFFF` | | | +| `libro.toptoolbar.border.color` | | `#FFFFFF1A` | `#0000001A` | | | +| `libro.toptoolbar.icon.color` | | `#BFBFBF` | `#7B7B7B` | | | +| `libro.toptoolbar.disabled.icon.color` | | `#FFFFFF4D` | `#00000040` | | | +| `libro.toptoolbar.text.color` | | `#F5F5F5` | `#000000` | | | +| `libro.bottom.btn.background.color` | | `#FFFFFF0A` | `#FFFFFF` | | | +| `libro.bottom.btn.border.color` | | `#505559` | `#000A1A29` | | | +| `libro.bottom.btn.icon.color` | | `#505559` | `#525964D9` | | | +| `libro.bottom.btn.text.color` | | `#E3E4E6` | `#000A1AAD` | | | +| `libro.default.btn.background.color` | | `#FFFFFF1A` | `#FFFFFF` | | | +| `libro.default.btn.text.color` | | `#E3E4E6` | `#000A1AAD` | | | +| `libro.primary.btn.background.color` | | `#2A97FD` | `#1890FF` | | | +| `libro.default.btn.border.color` | | `#BDC0C4` | `#D6D8DA` | | | +| `libro.toolbar.menu.label.color` | | `#BDC0C4` | `#000000A6` | | | +| `libro.toolbar.menu.disabled.label.color` | | `#878C93` | `#00000040` | | | +| `libro.toolbar.menu.keybind.color` | | `#878C93` | `#00000073` | | | +| `libro.sidetoolbar.icon.color` | | `#BFBFBF` | `#6982A9` | | | +| `libro.sidetoolbar.border.color` | | `#FFFFFF14` | `#0000001A` | | | +| `libro.close.color` | | `#FFFFFF73` | `#00000073` | | | +| `libro.modal.title.color` | | `#EDEEEF` | `#000000D9` | | | +| `libro.modal.content.color` | | `#E3E4E6` | `#000A1A` | | | +| `libro.btn.primary.background.color` | | `#2A97FD` | `#1890FF` | | | +| `libro.execution.count.color` | | `#8694A9` | `#6A83AA` | | | +| `libro.tip.font.color` | | `#D6D8DA` | `#00000080` | | | +| `libro.execution.tip.success.color` | | `#48A918` | `#0DC54E` | | | +| `libro.link.color` | | `#177DDC` | `#1890FF` | | | +| `libro.error.color` | | `#CF4C52` | `#ED1345` | | | +| `libro.cell.border.color` | | `#3B3C42` | `#D6DEE6` | | | +| `libro.cell.active.border.color` | | `#378EDF` | `#3490ED` | | | +| `libro.cell.active.border.shadow.color` | | `#49A2FA40` | `#3592EE40` | | | +| `libro.cell.header.content` | | `#E3E4E6` | `#545B66` | | | +| `libro.cell.header.title` | | `#D6D8DA` | `#000A1A` | | | +| `libro.code.border.color` | | `#353638` | `#DCE4EC` | | | +| `libro.input.border.color` | | `#505559` | `#00000026` | | | +| `libro.input.background.color` | | `#FFFFFF0A` | `#FFFFFF` | | | +| `libro.input.group.btn.background.color` | | `#00000005` | `#00000005` | | | +| `libro.table.innner.border.color` | | `#1AFFFF` | `#E5EBF1` | | | +| `libro.table.bottom.border.color` | | `#424242` | `#E2E7EC` | | | +| `libro.editor.keyword.color` | | `#109B67` | `#098658` | | | +| `libro.editor.number.color` | | `#109B67` | `#098658` | | | +| `libro.editor.variable.2.color` | | `#5DA4EA` | `#2060A0` | | | +| `libro.editor.punctuation.color` | | `#5DA4EA` | `#2060A0` | | | +| `libro.editor.property.color` | | `#5DA4EA` | `#2060A0` | | | +| `libro.editor.operator.color` | | `#E12EE1` | `#C700C7` | | | +| `libro.editor.meta.color` | | `#E12EE1` | `#C700C7` | | | +| `libro.editor.builtin.color` | | `#109B67` | `#098658` | | | +| `libro.editor.variable.color` | | `#E3E4E6` | `#212121` | | | +| `libro.editor.def.color` | | `#187DFF` | `#003CFF` | | | +| `libro.editor.comment.color` | | `#618961` | `#406040` | | | +| `libro.editor.string.color` | | `#FF5B48` | `#C03030` | | | +| `libro.editor.activeline.color` | | `#E5E8F01A` | `#E5E8F080` | | | +| `libro.editor.selectionMatch.color` | | `#99FF7780` | `#DDE6FF` | | | +| `libro.editor.selection.color` | | `#B4CEFF` | `#B4CEFF` | | | +| `libro.editor.gutter.number.color` | | `#A8EABF` | `#A4AECB` | | | +| `libro.editor.line.color` | | `#565C6D` | `#A4AECB` | | | +| `libro.editor.cursor.color` | | `#FFFFFF` | `#000000` | | | +| `libro.editor.indent.marker.bg.color` | | `#42444D` | `#D6DBEB` | | | +| `libro.editor.indent.marker.active.bg.color` | | `#788491` | `#9f9f9f` | | | diff --git a/web/packages/magent-flow/babel.config.json b/web/packages/magent-flow/babel.config.json new file mode 100644 index 0000000..efd1224 --- /dev/null +++ b/web/packages/magent-flow/babel.config.json @@ -0,0 +1,20 @@ +{ + "presets": [ + "@babel/preset-env", + [ + "@babel/preset-react", + { + "runtime": "automatic" + } + ], + "@babel/preset-typescript" + ], + "plugins": [ + ["@babel/plugin-proposal-decorators", { "legacy": true }], + ["@babel/plugin-transform-flow-strip-types", { "allowDeclareFields": true }], + ["@babel/plugin-transform-private-methods", { "loose": true }], + ["@babel/plugin-transform-private-property-in-object", { "loose": true }], + ["@babel/plugin-transform-class-properties", { "loose": true }], + "babel-plugin-parameter-decorator" + ] +} diff --git a/web/packages/magent-flow/jest.config.mjs b/web/packages/magent-flow/jest.config.mjs new file mode 100644 index 0000000..e698bd5 --- /dev/null +++ b/web/packages/magent-flow/jest.config.mjs @@ -0,0 +1,6 @@ +import configs from '../../../jest.config.mjs'; + +export default { + ...configs, + transformIgnorePatterns: ['^/node_modules/(?!react-dnd|dnd-core|@react-dnd)'], +}; diff --git a/web/packages/magent-flow/package.json b/web/packages/magent-flow/package.json new file mode 100644 index 0000000..397fd69 --- /dev/null +++ b/web/packages/magent-flow/package.json @@ -0,0 +1,78 @@ +{ + "name": "@difizen/magent-flow", + "version": "0.0.1", + "description": "", + "keywords": [ + "flow", + "ai", + "workflow" + ], + "type": "module", + "repository": "git@github.com:difizen/magent.git", + "license": "MIT", + "exports": { + ".": { + "typings": "./es/index.d.ts", + "default": "./es/index.js" + }, + "./mock": { + "typings": "./es/mock/index.d.ts", + "default": "./es/mock/index.js" + }, + "./es/mock": { + "typings": "./es/mock/index.d.ts", + "default": "./es/mock/index.js" + }, + "./package.json": "./package.json" + }, + "main": "es/index.js", + "module": "es/index.js", + "typings": "es/index.d.ts", + "files": [ + "es", + "src" + ], + "scripts": { + "setup": "father build", + "build": "father build", + "test": ": Note: lint task is delegated to test:* scripts", + "test:vitest": "vitest run", + "test:jest": "jest", + "coverage": ": Note: lint task is delegated to coverage:* scripts", + "coverage:vitest": "vitest run --coverage", + "coverage:jest": "jest --coverage", + "lint": ": Note: lint task is delegated to lint:* scripts", + "lint:eslint": "eslint src", + "tailwind": "tailwindcss -i ./src/tailwind.css -o ./src/tailwind.out.css --watch", + "typecheck:tsc": "tsc --noEmit" + }, + "dependencies": { + "@ant-design/icons": "^5.1.0", + "@babel/runtime": "^7.18.0", + "@floating-ui/react": "^0.26.22", + "@lexical/react": "^0.17.0", + "@types/json-schema": "^7.0.15", + "@xyflow/react": "^12.0.2", + "antd": "^5.19.2", + "ajv": "^8.17.1", + "js-yaml": "^4.1.0", + "lexical": "^0.17.0", + "lodash": "^4.17.21", + "react-hotkeys-hook": "^4.5.0", + "short-unique-id": "^5.2.0", + "styled-components": "^6.0.7", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "uuid": "^10.0.0", + "zustand": "^4.5.4" + }, + "devDependencies": { + "@types/react": "^18.2.25", + "@types/uuid": "^10.0.0", + "tailwindcss": "^3" + }, + "peerDependencies": { + "antd": "^5.8.6", + "react": ">=16" + } +} diff --git a/web/packages/magent-flow/src/FormSchema/index.ts b/web/packages/magent-flow/src/FormSchema/index.ts new file mode 100644 index 0000000..e1ac908 --- /dev/null +++ b/web/packages/magent-flow/src/FormSchema/index.ts @@ -0,0 +1,331 @@ +import { message } from 'antd'; +import type { + JSONSchema7, + JSONSchema7Definition, + JSONSchema7TypeName, +} from 'json-schema'; + +import { UUID } from '@/spec/uuid'; + +export type OrderJSONSchema7 = JSONSchema7 & { + order: number; +}; + +export interface CascaderOptions { + value: string; + label: string; + children?: CascaderOptions[]; +} + +/** + * 声明输入的表单数据格式 + * 表单内容 + */ +export class FormSchema { + uuid = UUID.getInstance().uniqueID(); + + jsonschema: JSONSchema7 = { + $id: this.uuid, + type: 'object', + properties: {}, + required: [], + }; + + constructor(schema: JSONSchema7) { + Object.assign(this.jsonschema, schema); + } + /** + * 获取指定路径的属性 + * 方便添加属性 + * /a/b/c/ + * @param pointer + * @returns + */ + getSchemaByPoint(pointer: string) { + if (pointer === '/' || pointer === '') { + return this.jsonschema; + } + + let pointers = pointer.split('/'); + if (pointers[0] !== '') { + throw new Error('invalid pointer'); + } + pointers = pointers.slice(1); + + // base是一个object模式 + let schema = this.jsonschema; + while (pointers.length > 0) { + const pointer = pointers.shift(); + if (pointer === undefined) { + throw new Error('invalid pointer'); + } + if (schema) { + if (schema.type === 'object') { + if (schema?.properties?.[pointer]) { + // 有就递归下沉 + schema = schema.properties[pointer] as JSONSchema7; + } else { + // 没有属性就添加 + schema!.properties![pointer] = {}; + return schema!.properties![pointer]; + } + } else if (schema?.type === 'array') { + if (schema?.items) { + const index = parseInt(pointer); + if (Array.isArray(schema.items)) { + schema = schema.items[index] as JSONSchema7; + } else { + schema = schema.items as JSONSchema7; + } + } + } + } + } + return schema; + } + + private randommName = () => { + return ( + 'RandaomName__-' + + Math.random().toString(36).substring(2, 15) + + Math.random().toString(36).substring(2, 15) + ); + }; + + isRandomName = (name: string) => { + return name.startsWith('RandaomName__-'); + }; + + /** + * 动态表单添加属性 + * @param property + * @returns + */ + addField = (options: { + pointer: string; // 指定属性路径,如 /a/b + name?: string; + type: JSONSchema7TypeName; + description: string; + required: boolean; + }) => { + const { pointer, name = this.randommName(), type, description, required } = options; + if (typeof this.jsonschema !== 'boolean') { + const schema = this.getSchemaByPoint(pointer); + if (schema.type === 'array') { + // 如果存在属性 + if (!schema?.items) { + schema.items = { + type: type, + description, + }; + } else if (!Array.isArray(schema?.items)) { + const items = schema.items as JSONSchema7Definition; + schema.items = [ + items, + { + type: type, + description, + }, + ]; + } else if (Array.isArray(schema?.items)) { + schema.items.push({ + type: type, + description, + }); + } + } else if (schema?.type === 'object') { + // 使用order 记录顺序 + let order = 0; + Object.entries(schema.properties || {}).forEach(([, val]) => { + const v = val as OrderJSONSchema7; + if (v?.order) { + order = v?.order > order ? v?.order : order; + } + }); + + (schema.properties![name] as OrderJSONSchema7) = { + type: type, + description, + order: order + 1, + }; + if (type === 'object') { + schema.properties![name].properties = {}; + } + } else { + schema.type = type; + schema.description = description; + } + if (required) { + // 如果是object的话,require在当前位置添加 + if (schema.type === 'object') { + if (!schema.required) { + schema.required = []; + } + schema.required = [...schema.required, name]; + } else { + // 在父级添加 + const parentPointer = pointer.split('/').slice(0, -1).join('/'); + const parentSchema = this.getSchemaByPoint(parentPointer); + + if (!parentSchema.required) { + parentSchema.required = []; + } + parentSchema.required = [...parentSchema.required, name]; + } + } + } + return false; + }; + + /** + * 动态表单更新属性 + * @param property + * @returns + */ + updateField = (options: { + pointer: string; // 指定属性路径,如 /a/b + key: 'variableName' | 'variableType' | 'description' | 'required'; + value: any; + currentVariableName: string; + }) => { + const { pointer, key, value, currentVariableName } = options; + if (typeof this.jsonschema !== 'boolean') { + const schema = this.getSchemaByPoint(pointer); + if (schema.type === 'object') { + if (schema.properties) { + if (key === 'variableName') { + const old = schema.properties?.[currentVariableName]; + if (value !== currentVariableName) { + schema.properties[value] = old; + delete schema.properties[currentVariableName]; + } else { + message.info('变量名不能和已有变量名相同'); + return false; + } + return true; + } + if (key === 'variableType') { + if ((schema.properties[currentVariableName] as JSONSchema7).type) { + // 处理数组类型 + if (value.startsWith('Array<')) { + const t = ( + value.replace('Array<', '').replace('>', '') as string + ).toLocaleLowerCase(); + schema.properties[currentVariableName].type = 'array'; + schema.properties[currentVariableName].items = { + type: t, + }; + if (t === 'object') { + schema.properties[currentVariableName].items.properties = {}; + } + return true; + } + if (value === 'object') { + schema.properties[currentVariableName].type = value; + schema.properties[currentVariableName].properties = {}; + return true; + } + + // 基础类型 + schema.properties[currentVariableName].type = value; + delete schema.properties[currentVariableName].items; + delete schema.properties[currentVariableName].properties; + + return true; + } + } + if (key === 'description') { + if (schema.properties[currentVariableName] as JSONSchema7) { + schema.properties[currentVariableName].description = value; + return true; + } + } + if (key === 'required') { + if (!this.isRandomName(currentVariableName)) { + if (schema.properties[currentVariableName]) { + if (!schema.required) { + schema.required = []; + } + if (value) { + if (!schema.required?.includes(value)) { + schema.required?.push(currentVariableName); + } + } else { + if (schema.required?.includes(currentVariableName)) { + schema.required = schema.required.filter( + (item) => item !== currentVariableName, + ); + } + } + + return true; + } + } + } + } + } + } + return false; + }; + + updateSchema(schema: JSONSchema7) { + Object.assign(this.jsonschema, schema); + } + + log() { + return JSON.stringify(this.jsonschema, null, 4); + } +} + +export const variableTypeOptions: { + label: string; + value: + | JSONSchema7TypeName + | 'Array' + | 'Array' + | 'Array' + | 'Array' + | 'Array'; +}[] = [ + { + label: 'String', + value: 'string', + }, + { + label: 'Integer', + value: 'integer', + }, + { + label: 'Boolean', + value: 'boolean', + }, + { + label: 'Number', + value: 'number', + }, + { + label: 'Object', + value: 'object', + }, + + { + label: 'Array', + value: 'Array', + }, + { + label: 'Array', + value: 'Array', + }, + { + label: 'Array', + value: 'Array', + }, + { + label: 'Array', + value: 'Array', + }, + { + label: 'Array', + value: 'Array', + }, +]; diff --git a/web/packages/magent-flow/src/RefForm/index.md b/web/packages/magent-flow/src/RefForm/index.md new file mode 100644 index 0000000..d2676dc --- /dev/null +++ b/web/packages/magent-flow/src/RefForm/index.md @@ -0,0 +1,31 @@ +--- +title: RefForm +group: { title: 'Schema', order: 2 } +toc: menu +order: 1 +demo: { cols: 2 } +--- + +## 基本用法 + +> 渲染输入参数表单,支持传入节点引用数据 + +```jsx +import React from 'react'; +import { RefForm, FormSchema, StartNode } from '@alipay/ai-workflow'; + +const startNode = new StartNode(); +startNode.config.inputs.updateSchema({ + type: 'object', + properties: { + name: { + type: 'string', + title: '姓名', + }, + }, +}); + +export default () => Hi, bigfish; +``` + + diff --git a/web/packages/magent-flow/src/RefForm/index.tsx b/web/packages/magent-flow/src/RefForm/index.tsx new file mode 100644 index 0000000..2df74aa --- /dev/null +++ b/web/packages/magent-flow/src/RefForm/index.tsx @@ -0,0 +1,292 @@ +import { CaretRightOutlined } from '@ant-design/icons'; +import { Button, Cascader, Collapse, Flex, Input, Select, Space, theme } from 'antd'; +import React, { useEffect, useMemo, useState } from 'react'; + +import type { NodeDataType } from '@/interfaces/flow'; + +interface CascaderOptions { + value: string; + label: string; + children?: CascaderOptions[]; +} + +/** + * 把jsonschema 转成cascader的options + */ +const getCascaderOptions = (node: NodeDataType) => { + const jsonSchema = node.config?.inputs?.jsonschema; + console.log('🚀 ~ getCascaderOptions ~ jsonSchema:', jsonSchema); + const options: CascaderOptions[] = [ + { + label: `${node.name}`, + value: node?.name, + children: [], + }, + ]; + + // 递归解析JSONSchema + const parseSchema = (schema: any): CascaderOptions[] => { + console.log('🚀 ~ parseSchema ~ schema:', schema); + const parsedOptions: CascaderOptions[] = []; + + for (const key in schema.properties) { + if (Object.hasOwn(schema.properties, key)) { + const type = schema.properties[key]?.type; + const label = `${key}-${type}`; + if (type === 'object') { + const childOptions: CascaderOptions[] = parseSchema(schema.properties[key]); + parsedOptions.push({ + value: key, + label: label, + children: childOptions, + }); + } else { + parsedOptions.push({ + value: key, + label: label, + }); + } + } + } + return parsedOptions; + }; + + if (jsonSchema && typeof jsonSchema === 'object') { + for (const key in jsonSchema.properties) { + if (Object.hasOwn(jsonSchema.properties, key)) { + const type = jsonSchema.properties[key]?.type; + const label = `${key}-${type}`; + + const rootOptions: CascaderOptions[] = options[0]! + .children as CascaderOptions[]; + + if (type === 'object') { + const childOptions: CascaderOptions[] = parseSchema( + jsonSchema.properties[key], + ); + rootOptions.push({ + value: key, + label: label, + children: childOptions, + }); + } else { + rootOptions.push({ + value: key, + label: label, + }); + } + } + } + } + + return options; +}; + +interface ParameterValue { + variableName: string; + variableType: 'ref' | 'input'; + variableValue: string | string[]; +} + +const Parameter = (props: { + flowNodes?: NodeDataType[]; + onChange?: (values: ParameterValue) => void; + values?: ParameterValue; +}) => { + const { flowNodes = [], onChange } = props; + + const [value, setValue] = useState({ + variableName: '', + variableType: 'ref', + variableValue: '', + }); + + const options: CascaderOptions[] = useMemo(() => { + let opt = [] as CascaderOptions[]; + flowNodes.forEach((v) => { + opt = [...opt, ...getCascaderOptions(v)]; + }); + return opt; + }, [flowNodes]); + + useEffect(() => { + onChange?.(value); + }, [value]); + + useEffect(() => { + if (props.values) { + setValue(props.values); + } + }, [props.values]); + + return ( + + { + setValue((s) => { + return { + ...s, + variableName: v.target.value, + }; + }); + }} + /> + + {value.variableType === 'ref' ? ( + { + console.log('🚀 ~ v:', v); + setValue((s) => { + return { + ...s, + variableValue: v, + }; + }); + }} + placeholder="Please select" + /> + ) : ( + { + setValue((s) => { + return { + ...s, + variableValue: v.target.value, + }; + }); + }} + /> + )} + + ); +}; + +/** + * 支持引用的表单 + * @returns + */ +export const RefForm = (props: { + flowNodes?: NodeDataType[]; + values?: ParameterValue[]; + onChange?: (values: ParameterValue[]) => void; +}) => { + const { flowNodes = [] } = props; + + const { token } = theme.useToken(); + + const panelStyle: React.CSSProperties = { + marginBottom: 24, + background: token.colorFillAlter, + borderRadius: token.borderRadiusLG, + border: 'none', + }; + + const [values, setValues] = useState([ + { + variableName: '', + variableType: 'ref', + variableValue: '', + }, + ]); + + useEffect(() => { + if (props.values) { + setValues(props.values); + } + }, [props.values]); + + useEffect(() => { + props.onChange?.(values); + }, [values]); + + const renderParamters = useMemo(() => { + return values.map((v, i) => { + return ( + { + setValues((s) => { + return [...s.slice(0, i), val, ...s.slice(i + 1)]; + }); + }} + > + ); + }); + }, [values]); + + return ( +
+ } + style={{ background: token.colorBgContainer }} + items={[ + { + style: panelStyle, + key: '1', + label: '输入', + children: ( + + +
+ 参数名 +
+
+ 参考值 +
+
+ {renderParamters} +
+ +
+
+ ), + }, + ]} + >
+
+ ); +}; diff --git a/web/packages/magent-flow/src/SchemaConfigForm/index.md b/web/packages/magent-flow/src/SchemaConfigForm/index.md new file mode 100644 index 0000000..4e6e369 --- /dev/null +++ b/web/packages/magent-flow/src/SchemaConfigForm/index.md @@ -0,0 +1,29 @@ +--- +title: SchemaConfigForm +group: { title: 'Schema', order: 1 } +toc: menu +order: 1 +demo: { cols: 2 } +--- + +## 基础用法 + +用于渲染jsonschema config的表单,传入一个FormSchema + +```jsx +import React from 'react'; +import { SchemaConfigForm, FormSchema } from '@alipay/ai-workflow'; + +const mockSchema = new FormSchema(); +mockSchema.updateSchema({ + $schema: 'http://json-schema.org/draft-04/schema#', + type: 'object', + properties: {}, +}); + +export default () => ( + Hi, bigfish +); +``` + + diff --git a/web/packages/magent-flow/src/SchemaConfigForm/index.tsx b/web/packages/magent-flow/src/SchemaConfigForm/index.tsx new file mode 100644 index 0000000..6435a36 --- /dev/null +++ b/web/packages/magent-flow/src/SchemaConfigForm/index.tsx @@ -0,0 +1,369 @@ +/** + * 动态渲染Schema,输出表单卡片 + */ + +import { + AppstoreAddOutlined, + CaretRightOutlined, + MinusCircleOutlined, +} from '@ant-design/icons'; +import { Card, Checkbox, Collapse, Form, Input, Select, Space, theme } from 'antd'; +import type { JSONSchema7 } from 'json-schema'; +import React, { useState } from 'react'; + +import { variableTypeOptions } from '@/FormSchema'; +import type { FormSchema, OrderJSONSchema7 } from '@/FormSchema'; + +// import { +// FormSchema, +// OrderJSONSchema7, +// variableTypeOptions, +// } from '../spec/FormSchema'; + +const useForceUpdate = () => { + const [forceKey, update] = useState(0); + const forceUpdate = () => { + update((v) => v + 1); + }; + return { forceUpdate, forceKey }; +}; + +export const SchemaConfigForm = (props: { + formSchema: FormSchema; + showRequired?: boolean; +}) => { + const { formSchema, showRequired = false } = props; + + const jsonschema = formSchema.jsonschema; + const { forceUpdate } = useForceUpdate(); + + const { token } = theme.useToken(); + + const panelStyle: React.CSSProperties = { + marginBottom: 24, + background: token.colorFillAlter, + borderRadius: token.borderRadiusLG, + border: 'none', + }; + + const renderField = ( + schema: JSONSchema7, + pointer: string, + required?: string[], + parentIsArray?: boolean, + isFirstlevel?: boolean, + ) => { + const defaultCase = () => { + const pointers = pointer.split('/'); + const plen = pointer.split('/').length; + const variableName = pointers[plen - 1]; + + const parentPointer = pointer.substring(0, pointer.lastIndexOf('/')); + + let tmpVariableName = variableName; + + const variableType = schema.type as string; + + return ( + + + { + const targetVal = v.target.value; + // 更新key + const success = formSchema.updateField({ + pointer: parentPointer, + key: 'variableName', + value: targetVal, + currentVariableName: tmpVariableName, + }); + if (success) { + tmpVariableName = targetVal; + } + }} + onBlur={forceUpdate} + /> + + + + + + { + formSchema.updateField({ + pointer: parentPointer, + key: 'description', + value: v.target.value, + currentVariableName: variableName, + }); + }} + /> + + {showRequired && ( + + { + formSchema.updateField({ + pointer: parentPointer, + key: 'required', + value: v.target.checked, + currentVariableName: variableName, + }); + }} + > + + )} + {/* {}} /> */} + + ); + }; + switch (schema?.type) { + case 'object': { + const propertiesKeys = Object.keys(schema.properties || {}); + propertiesKeys.sort((a, b) => { + const p = schema.properties as { [key: string]: OrderJSONSchema7 }; + console.log(p[a].order, p[b]?.order, '==order'); + return (p[a]?.order || 999) - (p[b]?.order || 999); + }); + + return ( +
+ {!parentIsArray && !isFirstlevel && defaultCase()} + ( + + )} + items={[ + { + style: panelStyle, + key: '1', + label: isFirstlevel ? '输入' : pointer, + extra: ( + { + e.stopPropagation(); + + formSchema.addField({ + pointer: pointer, // 指定属性路径,如 /a/b + type: 'string', + description: '请描述变量的用途', + required: false, + }); + forceUpdate(); + }} + /> + ), + children: propertiesKeys.map((v) => { + const subItemPointer = + pointer === '/' ? pointer + v : pointer + '/' + v; + + return ( +
+ {renderField( + schema.properties?.[v] as JSONSchema7, + subItemPointer, + schema.required, + )} +
+ ); + }), + }, + ]} + style={{ background: token.colorBgContainer }} + >
+
+ ); + } + + case 'array': { + const items = ( + Array.isArray(schema.items) ? schema.items[0] : schema.items + ) as JSONSchema7; + + const itemIsObject = items.type === 'object'; + + const pointers = pointer.split('/'); + const plen = pointer.split('/').length; + const variableName = pointers[plen - 1]; + + const parentPointer = pointer.substring(0, pointer.lastIndexOf('/')); + + let tmpVariableName = variableName; + + let variableType = schema.type as string; + + if (schema.type === 'array') { + const items = ( + Array.isArray(schema.items) ? schema.items[0] : schema.items + ) as JSONSchema7; + if (items) { + variableType = `Array<${items?.type}>`; + } + } + + return ( +
+ + + { + const targetVal = v.target.value; + // 更新key + const success = formSchema.updateField({ + pointer: parentPointer, + key: 'variableName', + value: targetVal, + currentVariableName: tmpVariableName, + }); + if (success) { + tmpVariableName = targetVal; + } + }} + onBlur={forceUpdate} + /> + + + + + + { + formSchema.updateField({ + pointer: parentPointer, + key: 'description', + value: v.target.value, + currentVariableName: variableName, + }); + }} + /> + + + { + formSchema.updateField({ + pointer: parentPointer, + key: 'required', + value: v.target.checked, + currentVariableName: variableName, + }); + }} + > + + {}} /> + + {/* 对象才渲染子类型 */} + {itemIsObject && renderField(items, pointer + '/0', schema.required, true)} +
+ ); + } + + default: { + return defaultCase(); + } + } + }; + + return ( + + + {renderField(jsonschema, '/', jsonschema.required, false, true)} + + +
{formSchema.log()}
+
+
+ ); +}; diff --git a/web/packages/magent-flow/src/common/icons.ts b/web/packages/magent-flow/src/common/icons.ts new file mode 100644 index 0000000..42793c3 --- /dev/null +++ b/web/packages/magent-flow/src/common/icons.ts @@ -0,0 +1,3 @@ +// export const IconMap = { +// LLM: +// } diff --git a/web/packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx b/web/packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx new file mode 100644 index 0000000..05e606a --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx @@ -0,0 +1,14 @@ +import { classNames } from '@/utils'; +import { Cascader, CascaderProps } from 'antd'; +import React from 'react'; + +export const CascaderInNode = (props: CascaderProps) => { + return ( + triggerNode.parentElement} + /> + ); +}; diff --git a/web/packages/magent-flow/src/components/AIBasic/CollapseWrapper/index.tsx b/web/packages/magent-flow/src/components/AIBasic/CollapseWrapper/index.tsx new file mode 100644 index 0000000..d10c9ed --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/CollapseWrapper/index.tsx @@ -0,0 +1,30 @@ +import { CaretRightOutlined } from '@ant-design/icons'; +import { Collapse } from 'antd'; +import type { ReactNode } from 'react'; +import React from 'react'; + +export const CollapseWrapper = ({ + className, + label, + content, +}: { + className?: string; + label?: string | React.ReactNode; + content: ReactNode; +}) => { + return ( + } + items={[ + { + key: '1', + label: label || '', + children: content, + }, + ]} + /> + ); +}; diff --git a/web/packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx b/web/packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx new file mode 100644 index 0000000..768b512 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx @@ -0,0 +1,14 @@ +import { capitalizeFirstLetter } from '@/utils/basic'; +import React from 'react'; + +export const OutputVariable = (props: { name: string; type: string }) => { + const { name, type } = props; + return ( +
+
{name}
+
+ {capitalizeFirstLetter(type)} +
+
+ ); +}; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/constants.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/constants.tsx new file mode 100644 index 0000000..f66ae60 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/constants.tsx @@ -0,0 +1,3 @@ +export const UPDATE_DATASETS_EVENT_EMITTER = + 'prompt-editor-context-block-update-datasets'; +export const UPDATE_HISTORY_EVENT_EMITTER = 'prompt-editor-history-block-update-role'; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts new file mode 100644 index 0000000..bdb0239 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts @@ -0,0 +1,58 @@ +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import type { EntityMatch } from '@lexical/text'; +import { mergeRegister } from '@lexical/utils'; +import type { Klass, LexicalEditor, TextNode } from 'lexical'; +import { useCallback, useEffect } from 'react'; + +import type { CustomTextNode } from './plugins/custom-text/node'; +import { registerLexicalTextEntity } from './utils'; + +export function useLexicalTextEntity( + getMatch: (text: string) => null | EntityMatch, + targetNode: Klass, + createNode: (textNode: CustomTextNode) => T, +) { + const [editor] = useLexicalComposerContext(); + + useEffect(() => { + return mergeRegister( + ...registerLexicalTextEntity(editor, getMatch, targetNode, createNode), + ); + }, [createNode, editor, getMatch, targetNode]); +} + +export type MenuTextMatch = { + leadOffset: number; + matchingString: string; + replaceableString: string; +}; +export type TriggerFn = (text: string, editor: LexicalEditor) => MenuTextMatch | null; +export const PUNCTUATION = + '\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%\'"~=<>_:;'; +export function useBasicTypeaheadTriggerMatch( + trigger: string, + { minLength = 1, maxLength = 75 }: { minLength?: number; maxLength?: number }, +): TriggerFn { + return useCallback( + (text: string) => { + const validChars = `[${PUNCTUATION}\\s]`; + const TypeaheadTriggerRegex = new RegExp( + '(.*)(' + `[${trigger}]` + `((?:${validChars}){0,${maxLength}})` + ')$', + ); + const match = TypeaheadTriggerRegex.exec(text); + if (match !== null) { + const maybeLeadingWhitespace = match[1]; + const matchingString = match[3]; + if (matchingString.length >= minLength) { + return { + leadOffset: match.index + maybeLeadingWhitespace.length, + matchingString, + replaceableString: match[2], + }; + } + } + return null; + }, + [maxLength, minLength, trigger], + ); +} diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx new file mode 100644 index 0000000..06d12a8 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx @@ -0,0 +1,127 @@ +import { CodeNode } from '@lexical/code'; +import { LexicalComposer } from '@lexical/react/LexicalComposer'; +import { ContentEditable } from '@lexical/react/LexicalContentEditable'; +import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'; +import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'; +import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'; +import type { EditorState } from 'lexical'; +import { $getRoot, TextNode } from 'lexical'; +import React, { type FC } from 'react'; +import ComponentPickerBlock from './plugins/component-picker-block'; +import { CustomTextNode } from './plugins/custom-text/node'; +import OnBlurBlock from './plugins/on-blur-or-focus-block'; +import Placeholder from './plugins/placeholder'; +import UpdateBlock from './plugins/update-block'; +import VariableBlock from './plugins/variable-block'; +import VariableValueBlock from './plugins/variable-value-block'; +import { VariableValueBlockNode } from './plugins/variable-value-block/node'; +import type { ExternalToolBlockType, VariableBlockType } from './types'; +import { textToEditorState } from './utils'; + +export type PromptEditorProps = { + instanceId?: string; + compact?: boolean; + className?: string; + placeholder?: string; + placeholderClassName?: string; + style?: React.CSSProperties; + value?: string; + editable?: boolean; + onChange?: (text: string) => void; + onBlur?: () => void; + onFocus?: () => void; + variableBlock?: VariableBlockType; + externalToolBlock?: ExternalToolBlockType; +}; + +const PromptEditor: FC = ({ + instanceId, + compact, + className, + placeholder, + placeholderClassName, + style, + value, + editable = true, + onChange, + onBlur, + onFocus, + variableBlock, + externalToolBlock, +}) => { + const initialConfig = { + namespace: 'prompt-editor', + nodes: [ + CodeNode, + CustomTextNode, + { + replace: TextNode, + with: (node: TextNode) => new CustomTextNode(node.__text), + }, + VariableValueBlockNode, + ], + editorState: textToEditorState(value || ''), + onError: (error: Error) => { + throw error; + }, + }; + + const handleEditorChange = (editorState: EditorState) => { + const text = editorState.read(() => { + return $getRoot() + .getChildren() + .map((p) => p.getTextContent()) + .join('\n'); + }); + + if (onChange) onChange(text); + }; + + return ( + +
+ + } + placeholder={ + + } + ErrorBoundary={LexicalErrorBoundary} + /> + + + + {(variableBlock?.show || externalToolBlock?.show) && ( + <> + + + + )} + + + + {/* */} +
+
+ ); +}; + +export default PromptEditor; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx new file mode 100644 index 0000000..a48a7a0 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx @@ -0,0 +1,185 @@ +import { AndroidFilled } from '@ant-design/icons'; +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import { $insertNodes } from 'lexical'; +import React, { useMemo } from 'react'; + +import type { ExternalToolBlockType, VariableBlockType } from '../../types'; +import { $createCustomTextNode } from '../custom-text/node'; +import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../variable-block'; + +import { PickerBlockMenuOption } from './menu'; +import { VariableMenuItem } from './variable-option'; + +export const useVariableOptions = ( + variableBlock?: VariableBlockType, + queryString?: string, +): PickerBlockMenuOption[] => { + const [editor] = useLexicalComposerContext(); + + const options = useMemo(() => { + if (!variableBlock?.variables) { + return []; + } + + const baseOptions = variableBlock.variables.map((item) => { + return new PickerBlockMenuOption({ + key: item.value, + group: 'prompt variable', + render: ({ queryString, isSelected, onSelect, onSetHighlight }) => { + return ( + } + queryString={queryString} + isSelected={isSelected} + onClick={onSelect} + onMouseEnter={onSetHighlight} + /> + ); + }, + onSelect: () => { + editor.dispatchCommand( + INSERT_VARIABLE_VALUE_BLOCK_COMMAND, + `{{${item.value}}}`, + ); + }, + }); + }); + if (!queryString) { + return baseOptions; + } + + const regex = new RegExp(queryString, 'i'); + + return baseOptions.filter((option) => regex.test(option.key)); + }, [editor, queryString, variableBlock]); + + const addOption = useMemo(() => { + return new PickerBlockMenuOption({ + key: '添加新变量', + group: 'prompt variable', + render: ({ queryString, isSelected, onSelect, onSetHighlight }) => { + return ( + } + queryString={queryString} + isSelected={isSelected} + onClick={onSelect} + onMouseEnter={onSetHighlight} + /> + ); + }, + onSelect: () => { + editor.update(() => { + const prefixNode = $createCustomTextNode('{{'); + const suffixNode = $createCustomTextNode('}}'); + $insertNodes([prefixNode, suffixNode]); + prefixNode.select(); + }); + }, + }); + }, [editor]); + + return useMemo(() => { + return variableBlock?.show ? [...options, addOption] : []; + }, [options, addOption, variableBlock?.show]); +}; + +export const useExternalToolOptions = ( + externalToolBlockType?: ExternalToolBlockType, + queryString?: string, +) => { + const [editor] = useLexicalComposerContext(); + + const options = useMemo(() => { + if (!externalToolBlockType?.externalTools) { + return []; + } + const baseToolOptions = externalToolBlockType.externalTools.map((item) => { + return new PickerBlockMenuOption({ + key: item.name, + group: 'external tool', + render: ({ queryString, isSelected, onSelect, onSetHighlight }) => { + return ( + + } + extraElement={ +
{item.variableName}
+ } + queryString={queryString} + isSelected={isSelected} + onClick={onSelect} + onMouseEnter={onSetHighlight} + /> + ); + }, + onSelect: () => { + editor.dispatchCommand( + INSERT_VARIABLE_VALUE_BLOCK_COMMAND, + `{{${item.variableName}}}`, + ); + }, + }); + }); + if (!queryString) { + return baseToolOptions; + } + + const regex = new RegExp(queryString, 'i'); + + return baseToolOptions.filter((option) => regex.test(option.key)); + }, [editor, queryString, externalToolBlockType]); + + const addOption = useMemo(() => { + return new PickerBlockMenuOption({ + key: '添加工具', + group: 'external tool', + render: ({ queryString, isSelected, onSelect, onSetHighlight }) => { + return ( + } + extraElement={} + queryString={queryString} + isSelected={isSelected} + onClick={onSelect} + onMouseEnter={onSetHighlight} + /> + ); + }, + onSelect: () => { + externalToolBlockType?.onAddExternalTool?.(); + }, + }); + }, [externalToolBlockType]); + + return useMemo(() => { + return externalToolBlockType?.show ? [...options, addOption] : []; + }, [options, addOption, externalToolBlockType?.show]); +}; + +export const useOptions = ( + variableBlock?: VariableBlockType, + externalToolBlockType?: ExternalToolBlockType, + queryString?: string, +) => { + const variableOptions = useVariableOptions(variableBlock, queryString); + const externalToolOptions = useExternalToolOptions( + externalToolBlockType, + queryString, + ); + + return useMemo(() => { + return { + allFlattenOptions: [...variableOptions, ...externalToolOptions], + }; + }, [variableOptions, externalToolOptions]); +}; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx new file mode 100644 index 0000000..ddb64af --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx @@ -0,0 +1,168 @@ +import { flip, offset, shift, useFloating } from '@floating-ui/react'; +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import type { MenuRenderFn } from '@lexical/react/LexicalTypeaheadMenuPlugin'; +import { LexicalTypeaheadMenuPlugin } from '@lexical/react/LexicalTypeaheadMenuPlugin'; +import type { TextNode } from 'lexical'; +import React, { Fragment, memo, useCallback, useState } from 'react'; +import ReactDOM from 'react-dom'; + +import { useEventEmitterContextContext } from '@/context/event-emitter'; + +import { useBasicTypeaheadTriggerMatch } from '../../hooks'; +import type { ExternalToolBlockType, VariableBlockType } from '../../types'; +import { $splitNodeContainingQuery } from '../../utils'; +import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../variable-block'; + +import { useOptions } from './hooks'; +import type { PickerBlockMenuOption } from './menu'; + +type ComponentPickerProps = { + triggerString: string; + variableBlock?: VariableBlockType; + externalToolBlock?: ExternalToolBlockType; +}; +const ComponentPicker = ({ + triggerString, + variableBlock, + externalToolBlock, +}: ComponentPickerProps) => { + const { eventEmitter } = useEventEmitterContextContext(); + const { refs, floatingStyles, isPositioned } = useFloating({ + placement: 'bottom-start', + middleware: [ + offset(0), // fix hide cursor + shift({ + padding: 8, + }), + flip(), + ], + }); + const [editor] = useLexicalComposerContext(); + const checkForTriggerMatch = useBasicTypeaheadTriggerMatch(triggerString, { + minLength: 0, + maxLength: 0, + }); + + const [queryString, setQueryString] = useState(null); + + eventEmitter?.useSubscription((v: any) => { + if (v.type === INSERT_VARIABLE_VALUE_BLOCK_COMMAND) { + editor.dispatchCommand(INSERT_VARIABLE_VALUE_BLOCK_COMMAND, `{{${v.payload}}}`); + } + }); + + const { allFlattenOptions } = useOptions(variableBlock, externalToolBlock); + + const onSelectOption = useCallback( + ( + selectedOption: PickerBlockMenuOption, + nodeToRemove: TextNode | null, + closeMenu: () => void, + ) => { + editor.update(() => { + if (nodeToRemove && selectedOption?.key) { + nodeToRemove.remove(); + } + + selectedOption.onSelectMenuOption(); + closeMenu(); + }); + }, + [editor], + ); + + const handleSelectWorkflowVariable = useCallback( + (variables: string[]) => { + editor.update(() => { + const needRemove = $splitNodeContainingQuery( + checkForTriggerMatch(triggerString, editor)!, + ); + if (needRemove) { + needRemove.remove(); + } + }); + }, + [editor, checkForTriggerMatch, triggerString], + ); + + const renderMenu = useCallback>( + ( + anchorElementRef, + { options, selectedIndex, selectOptionAndCleanUp, setHighlightedIndex }, + ) => { + if (!(anchorElementRef.current && allFlattenOptions.length)) { + return null; + } + refs.setReference(anchorElementRef.current); + + return ( + <> + {ReactDOM.createPortal( + // The `LexicalMenu` will try to calculate the position of the floating menu based on the first child. + // Since we use floating ui, we need to wrap it with a div to prevent the position calculation being affected. + // See https://github.com/facebook/lexical/blob/ac97dfa9e14a73ea2d6934ff566282d7f758e8bb/packages/lexical-react/src/shared/LexicalMenu.ts#L493 +
+
+ {options.map((option, index) => ( + + { + // Divider + index !== 0 && options.at(index - 1)?.group !== option.group && ( +
+ ) + } + {option.renderMenuOption({ + queryString, + isSelected: selectedIndex === index, + onSelect: () => { + selectOptionAndCleanUp(option); + }, + onSetHighlight: () => { + setHighlightedIndex(index); + }, + })} +
+ ))} +
+
, + anchorElementRef.current, + )} + + ); + }, + [ + allFlattenOptions.length, + refs, + isPositioned, + floatingStyles, + queryString, + handleSelectWorkflowVariable, + ], + ); + + return ( + + ); +}; + +export default memo(ComponentPicker); diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/menu.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/menu.tsx new file mode 100644 index 0000000..ca21088 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/menu.tsx @@ -0,0 +1,33 @@ +import { MenuOption } from '@lexical/react/LexicalTypeaheadMenuPlugin'; +import { Fragment } from 'react'; + +/** + * Corresponds to the `MenuRenderFn` type from `@lexical/react/LexicalTypeaheadMenuPlugin`. + */ +type MenuOptionRenderProps = { + isSelected: boolean; + onSelect: () => void; + onSetHighlight: () => void; + queryString: string | null; +}; + +export class PickerBlockMenuOption extends MenuOption { + public group?: string; + + constructor( + private data: { + key: string; + group?: string; + onSelect?: () => void; + render: (menuRenderProps: MenuOptionRenderProps) => JSX.Element; + }, + ) { + super(data.key); + this.group = data.group; + } + + public onSelectMenuOption = () => this.data.onSelect?.(); + public renderMenuOption = (menuRenderProps: MenuOptionRenderProps) => ( + {this.data.render(menuRenderProps)} + ); +} diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx new file mode 100644 index 0000000..43ff4dc --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx @@ -0,0 +1,53 @@ +import React, { memo } from 'react'; + +type PromptMenuItemMenuItemProps = { + icon: JSX.Element; + title: string; + disabled?: boolean; + isSelected: boolean; + onClick: () => void; + onMouseEnter: () => void; + setRefElement?: (element: HTMLDivElement) => void; +}; + +export const PromptMenuItem = memo( + ({ + icon, + title, + disabled, + isSelected, + onClick, + onMouseEnter, + setRefElement, + }: PromptMenuItemMenuItemProps) => { + return ( +
{ + if (disabled) { + return; + } + onMouseEnter(); + }} + onClick={() => { + if (disabled) { + return; + } + onClick(); + }} + > + {icon} +
{title}
+
+ ); + }, +); +PromptMenuItem.displayName = 'PromptMenuItem'; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx new file mode 100644 index 0000000..2dce466 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx @@ -0,0 +1,61 @@ +import React, { memo } from 'react'; + +type VariableMenuItemProps = { + title: string; + icon?: JSX.Element; + extraElement?: JSX.Element; + isSelected: boolean; + queryString: string | null; + onClick: () => void; + onMouseEnter: () => void; + setRefElement?: (element: HTMLDivElement) => void; +}; +export const VariableMenuItem = memo( + ({ + title, + icon, + extraElement, + isSelected, + queryString, + onClick, + onMouseEnter, + setRefElement, + }: VariableMenuItemProps) => { + let before = title; + let middle = ''; + let after = ''; + + if (queryString) { + const regex = new RegExp(queryString, 'i'); + const match = regex.exec(title); + + if (match) { + before = title.substring(0, match.index); + middle = match[0]; + after = title.substring(match.index + match[0].length); + } + } + + return ( +
+
{icon}
+
+ {before} + {middle} + {after} +
+ {extraElement} +
+ ); + }, +); +VariableMenuItem.displayName = 'VariableMenuItem'; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx new file mode 100644 index 0000000..b660ce8 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx @@ -0,0 +1,53 @@ +import type { EditorConfig, NodeKey, SerializedTextNode } from 'lexical'; +import { $createTextNode, TextNode } from 'lexical'; + +export class CustomTextNode extends TextNode { + static getType() { + return 'custom-text'; + } + + static clone(node: CustomTextNode) { + return new CustomTextNode(node.__text, node.__key); + } + + constructor(text: string, key?: NodeKey) { + super(text, key); + } + + createDOM(config: EditorConfig) { + const dom = super.createDOM(config); + dom.classList.add('align-middle'); + return dom; + } + + static importJSON(serializedNode: SerializedTextNode): TextNode { + const node = $createTextNode(serializedNode.text); + node.setFormat(serializedNode.format); + node.setDetail(serializedNode.detail); + node.setMode(serializedNode.mode); + node.setStyle(serializedNode.style); + return node; + } + + exportJSON(): SerializedTextNode { + return { + detail: this.getDetail(), + format: this.getFormat(), + mode: this.getMode(), + style: this.getStyle(), + text: this.getTextContent(), + type: 'custom-text', + version: 1, + }; + } + + isSimpleText() { + return ( + (this.__type === 'text' || this.__type === 'custom-text') && this.__mode === 0 + ); + } +} + +export function $createCustomTextNode(text: string): CustomTextNode { + return new CustomTextNode(text); +} diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx new file mode 100644 index 0000000..d7de68c --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx @@ -0,0 +1,53 @@ +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import { mergeRegister } from '@lexical/utils'; +import { + BLUR_COMMAND, + COMMAND_PRIORITY_EDITOR, + FOCUS_COMMAND, + KEY_ESCAPE_COMMAND, +} from 'lexical'; +import type { FC } from 'react'; +import { useEffect, useRef } from 'react'; + +type OnBlurBlockProps = { + onBlur?: () => void; + onFocus?: () => void; +}; +const OnBlurBlock: FC = ({ onBlur, onFocus }) => { + const [editor] = useLexicalComposerContext(); + + const ref = useRef(null); + + useEffect(() => { + return mergeRegister( + editor.registerCommand( + BLUR_COMMAND, + () => { + ref.current = setTimeout(() => { + editor.dispatchCommand( + KEY_ESCAPE_COMMAND, + new KeyboardEvent('keydown', { key: 'Escape' }), + ); + }, 200); + + if (onBlur) onBlur(); + + return true; + }, + COMMAND_PRIORITY_EDITOR, + ), + editor.registerCommand( + FOCUS_COMMAND, + () => { + if (onFocus) onFocus(); + return true; + }, + COMMAND_PRIORITY_EDITOR, + ), + ); + }, [editor, onBlur, onFocus]); + + return null; +}; + +export default OnBlurBlock; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx new file mode 100644 index 0000000..a98915a --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx @@ -0,0 +1,26 @@ +import classNames from 'classnames'; +import React, { memo } from 'react'; + +const Placeholder = ({ + compact, + value, + className, +}: { + compact?: boolean; + value?: string; + className?: string; +}) => { + return ( +
+ {value || "在这里写你的提示词,输入'{' 插入变量"} +
+ ); +}; + +export default memo(Placeholder); diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx new file mode 100644 index 0000000..c7ca926 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx @@ -0,0 +1,45 @@ +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import { $insertNodes } from 'lexical'; + +import { useEventEmitterContextContext } from '@/context/event-emitter'; + +import { textToEditorState } from '../utils'; + +import { CustomTextNode } from './custom-text/node'; + +export const PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER = + 'PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER'; +export const PROMPT_EDITOR_INSERT_QUICKLY = 'PROMPT_EDITOR_INSERT_QUICKLY'; + +type UpdateBlockProps = { + instanceId?: string; +}; +const UpdateBlock = ({ instanceId }: UpdateBlockProps) => { + const { eventEmitter } = useEventEmitterContextContext(); + + const [editor] = useLexicalComposerContext(); + + eventEmitter?.useSubscription((v: any) => { + if ( + v.type === PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER && + v.instanceId === instanceId + ) { + const editorState = editor.parseEditorState(textToEditorState(v.payload)); + editor.setEditorState(editorState); + } + }); + + eventEmitter?.useSubscription((v: any) => { + if (v.type === PROMPT_EDITOR_INSERT_QUICKLY && v.instanceId === instanceId) { + editor.focus(); + editor.update(() => { + const textNode = new CustomTextNode('/'); + $insertNodes([textNode]); + }); + } + }); + + return null; +}; + +export default UpdateBlock; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx new file mode 100644 index 0000000..b1dc0bd --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx @@ -0,0 +1,46 @@ +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import { mergeRegister } from '@lexical/utils'; +import { $insertNodes, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical'; +import { useEffect } from 'react'; + +import { CustomTextNode } from '../custom-text/node'; + +export const INSERT_VARIABLE_BLOCK_COMMAND = createCommand( + 'INSERT_VARIABLE_BLOCK_COMMAND', +); +export const INSERT_VARIABLE_VALUE_BLOCK_COMMAND = createCommand( + 'INSERT_VARIABLE_VALUE_BLOCK_COMMAND', +); + +const VariableBlock = () => { + const [editor] = useLexicalComposerContext(); + + useEffect(() => { + return mergeRegister( + editor.registerCommand( + INSERT_VARIABLE_BLOCK_COMMAND, + () => { + const textNode = new CustomTextNode('{'); + $insertNodes([textNode]); + + return true; + }, + COMMAND_PRIORITY_EDITOR, + ), + editor.registerCommand( + INSERT_VARIABLE_VALUE_BLOCK_COMMAND, + (value: string) => { + const textNode = new CustomTextNode(value); + $insertNodes([textNode]); + + return true; + }, + COMMAND_PRIORITY_EDITOR, + ), + ); + }, [editor]); + + return null; +}; + +export default VariableBlock; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx new file mode 100644 index 0000000..51a4784 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx @@ -0,0 +1,55 @@ +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import type { TextNode } from 'lexical'; +import { useCallback, useEffect } from 'react'; + +import { useLexicalTextEntity } from '../../hooks'; + +import { $createVariableValueBlockNode, VariableValueBlockNode } from './node'; +import { getHashtagRegexString } from './utils'; + +const REGEX = new RegExp(getHashtagRegexString(), 'i'); + +const VariableValueBlock = () => { + const [editor] = useLexicalComposerContext(); + + useEffect(() => { + if (!editor.hasNodes([VariableValueBlockNode])) { + throw new Error( + 'VariableValueBlockPlugin: VariableValueNode not registered on editor', + ); + } + }, [editor]); + + const createVariableValueBlockNode = useCallback( + (textNode: TextNode): VariableValueBlockNode => { + return $createVariableValueBlockNode(textNode.getTextContent()); + }, + [], + ); + + const getVariableValueMatch = useCallback((text: string) => { + const matchArr = REGEX.exec(text); + + if (matchArr === null) { + return null; + } + + const hashtagLength = matchArr[0].length; + const startOffset = matchArr.index; + const endOffset = startOffset + hashtagLength; + return { + end: endOffset, + start: startOffset, + }; + }, []); + + useLexicalTextEntity( + getVariableValueMatch, + VariableValueBlockNode, + createVariableValueBlockNode, + ); + + return null; +}; + +export default VariableValueBlock; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx new file mode 100644 index 0000000..a53ebca --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx @@ -0,0 +1,65 @@ +import type { EditorConfig, LexicalNode, NodeKey, SerializedTextNode } from 'lexical'; +import { $applyNodeReplacement, TextNode } from 'lexical'; + +export class VariableValueBlockNode extends TextNode { + static getType(): string { + return 'variable-value-block'; + } + + static clone(node: VariableValueBlockNode): VariableValueBlockNode { + return new VariableValueBlockNode(node.__text, node.__key); + } + + constructor(text: string, key?: NodeKey) { + super(text, key); + } + + createDOM(config: EditorConfig): HTMLElement { + const element = super.createDOM(config); + element.classList.add( + 'inline-flex', + 'items-center', + 'px-0.5', + 'h-[22px]', + 'text-[#155EEF]', + 'rounded-[5px]', + 'align-middle', + ); + return element; + } + + static importJSON(serializedNode: SerializedTextNode): TextNode { + const node = $createVariableValueBlockNode(serializedNode.text); + node.setFormat(serializedNode.format); + node.setDetail(serializedNode.detail); + node.setMode(serializedNode.mode); + node.setStyle(serializedNode.style); + return node; + } + + exportJSON(): SerializedTextNode { + return { + detail: this.getDetail(), + format: this.getFormat(), + mode: this.getMode(), + style: this.getStyle(), + text: this.getTextContent(), + type: 'variable-value-block', + version: 1, + }; + } + + canInsertTextBefore(): boolean { + return false; + } +} + +export function $createVariableValueBlockNode(text = ''): VariableValueBlockNode { + return $applyNodeReplacement(new VariableValueBlockNode(text)); +} + +export function $isVariableValueNodeBlock( + node: LexicalNode | null | undefined, +): node is VariableValueBlockNode { + return node instanceof VariableValueBlockNode; +} diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/utils.ts b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/utils.ts new file mode 100644 index 0000000..2798688 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/utils.ts @@ -0,0 +1,5 @@ +export function getHashtagRegexString(): string { + const hashtag = '\\{\\{[a-zA-Z_][a-zA-Z0-9_]{0,29}\\}\\}'; + + return hashtag; +} diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/types.ts b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/types.ts new file mode 100644 index 0000000..b03f417 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/types.ts @@ -0,0 +1,28 @@ +export type Option = { + value: string; + name: string; +}; + +export type ExternalToolOption = { + name: string; + variableName: string; + icon?: string; + icon_background?: string; +}; + +export type VariableBlockType = { + show?: boolean; + variables?: Option[]; +}; + +export type ExternalToolBlockType = { + show?: boolean; + externalTools?: ExternalToolOption[]; + onAddExternalTool?: () => void; +}; + +export type MenuTextMatch = { + leadOffset: number; + matchingString: string; + replaceableString: string; +}; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts new file mode 100644 index 0000000..eb8a4bc --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts @@ -0,0 +1,260 @@ +import type { EntityMatch } from '@lexical/text'; +import type { Klass, LexicalEditor, LexicalNode, TextNode } from 'lexical'; +import { + $createTextNode, + $getSelection, + $isRangeSelection, + $isTextNode, +} from 'lexical'; + +import { CustomTextNode } from './plugins/custom-text/node'; +import type { MenuTextMatch } from './types'; + +export function registerLexicalTextEntity( + editor: LexicalEditor, + getMatch: (text: string) => null | EntityMatch, + targetNode: Klass, + createNode: (textNode: TextNode) => T, +) { + const isTargetNode = (node: LexicalNode | null | undefined): node is T => { + return node instanceof targetNode; + }; + + const replaceWithSimpleText = (node: TextNode): void => { + const textNode = $createTextNode(node.getTextContent()); + textNode.setFormat(node.getFormat()); + node.replace(textNode); + }; + + const getMode = (node: TextNode): number => { + return node.getLatest().__mode; + }; + + const textNodeTransform = (node: TextNode) => { + if (!node.isSimpleText()) { + return; + } + + const prevSibling = node.getPreviousSibling(); + + let text = node.getTextContent(); + let currentNode = node; + let match; + + if ($isTextNode(prevSibling)) { + const previousText = prevSibling.getTextContent(); + const combinedText = previousText + text; + const prevMatch = getMatch(combinedText); + + if (isTargetNode(prevSibling)) { + if (prevMatch === null || getMode(prevSibling) !== 0) { + replaceWithSimpleText(prevSibling); + return; + } else { + const diff = prevMatch.end - previousText.length; + + if (diff > 0) { + const concatText = text.slice(0, diff); + const newTextContent = previousText + concatText; + prevSibling.select(); + prevSibling.setTextContent(newTextContent); + + if (diff === text.length) { + node.remove(); + } else { + const remainingText = text.slice(diff); + node.setTextContent(remainingText); + } + + return; + } + } + } else if (prevMatch === null || prevMatch.start < previousText.length) { + return; + } + } + + while (true) { + match = getMatch(text); + let nextText = match === null ? '' : text.slice(match.end); + text = nextText; + + if (nextText === '') { + const nextSibling = currentNode.getNextSibling(); + + if ($isTextNode(nextSibling)) { + nextText = currentNode.getTextContent() + nextSibling.getTextContent(); + const nextMatch = getMatch(nextText); + + if (nextMatch === null) { + if (isTargetNode(nextSibling)) { + replaceWithSimpleText(nextSibling); + } else { + nextSibling.markDirty(); + } + + return; + } else if (nextMatch.start !== 0) { + return; + } + } + } else { + const nextMatch = getMatch(nextText); + + if (nextMatch !== null && nextMatch.start === 0) { + return; + } + } + + if (match === null) { + return; + } + + if (match.start === 0 && $isTextNode(prevSibling) && prevSibling.isTextEntity()) { + continue; + } + + let nodeToReplace; + + if (match.start === 0) { + [nodeToReplace, currentNode] = currentNode.splitText(match.end); + } else { + [, nodeToReplace, currentNode] = currentNode.splitText(match.start, match.end); + } + + const replacementNode = createNode(nodeToReplace); + replacementNode.setFormat(nodeToReplace.getFormat()); + nodeToReplace.replace(replacementNode); + + if (currentNode == null) { + return; + } + } + }; + + const reverseNodeTransform = (node: T) => { + const text = node.getTextContent(); + const match = getMatch(text); + + if (match === null || match.start !== 0) { + replaceWithSimpleText(node); + return; + } + + if (text.length > match.end) { + // This will split out the rest of the text as simple text + node.splitText(match.end); + return; + } + + const prevSibling = node.getPreviousSibling(); + + if ($isTextNode(prevSibling) && prevSibling.isTextEntity()) { + replaceWithSimpleText(prevSibling); + replaceWithSimpleText(node); + } + + const nextSibling = node.getNextSibling(); + + if ($isTextNode(nextSibling) && nextSibling.isTextEntity()) { + replaceWithSimpleText(nextSibling); // This may have already been converted in the previous block + + if (isTargetNode(node)) { + replaceWithSimpleText(node); + } + } + }; + + const removePlainTextTransform = editor.registerNodeTransform( + CustomTextNode, + textNodeTransform, + ); + const removeReverseNodeTransform = editor.registerNodeTransform( + targetNode, + reverseNodeTransform, + ); + return [removePlainTextTransform, removeReverseNodeTransform]; +} + +function getFullMatchOffset( + documentText: string, + entryText: string, + offset: number, +): number { + let triggerOffset = offset; + for (let i = triggerOffset; i <= entryText.length; i++) { + if (documentText.substr(-i) === entryText.substr(0, i)) { + triggerOffset = i; + } + } + return triggerOffset; +} + +export function $splitNodeContainingQuery(match: MenuTextMatch): TextNode | null { + const selection = $getSelection(); + if (!$isRangeSelection(selection) || !selection.isCollapsed()) { + return null; + } + const anchor = selection.anchor; + if (anchor.type !== 'text') { + return null; + } + const anchorNode = anchor.getNode(); + if (!anchorNode.isSimpleText()) { + return null; + } + const selectionOffset = anchor.offset; + const textContent = anchorNode.getTextContent().slice(0, selectionOffset); + const characterOffset = match.replaceableString.length; + const queryOffset = getFullMatchOffset( + textContent, + match.matchingString, + characterOffset, + ); + const startOffset = selectionOffset - queryOffset; + if (startOffset < 0) { + return null; + } + let newNode; + if (startOffset === 0) { + [newNode] = anchorNode.splitText(selectionOffset); + } else { + [, newNode] = anchorNode.splitText(startOffset, selectionOffset); + } + + return newNode; +} + +export function textToEditorState(text: string) { + const paragraph = text.split('\n'); + + return JSON.stringify({ + root: { + children: paragraph.map((p) => { + return { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: p, + type: 'custom-text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'paragraph', + version: 1, + }; + }), + direction: 'ltr', + format: '', + indent: 0, + type: 'root', + version: 1, + }, + }); +} diff --git a/web/packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx b/web/packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx new file mode 100644 index 0000000..2890d07 --- /dev/null +++ b/web/packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx @@ -0,0 +1,13 @@ +import { classNames } from '@/utils'; +import { Select, SelectProps } from 'antd'; +import React from 'react'; + +export const SelectInNode = (props: SelectProps) => { + return ( + + ); +}; diff --git a/web/packages/magent-flow/src/components/CustomEdge/index.tsx b/web/packages/magent-flow/src/components/CustomEdge/index.tsx new file mode 100644 index 0000000..a1baf20 --- /dev/null +++ b/web/packages/magent-flow/src/components/CustomEdge/index.tsx @@ -0,0 +1,61 @@ +import { BaseEdge, EdgeProps, getBezierPath, MarkerType } from '@xyflow/react'; +import React from 'react'; + +export default function CustomEdge({ + // id, + sourceX, + sourceY, + targetX, + targetY, + sourcePosition, + targetPosition, + style = {}, + markerEnd, + selected, +}: EdgeProps) { + // const { setNodes } = useReactFlow(); + const [edgePath] = getBezierPath({ + sourceX, + sourceY, + sourcePosition, + targetX, + targetY, + targetPosition, + }); + + // const onEdgeClick = () => { + // Modal.Open(
addNode
); + // }; + return ( + <> + + {/* {selected && ( + +
+
+
+
+
+
+
+ )} */} + + ); +} diff --git a/web/packages/magent-flow/src/components/Flow/index.tsx b/web/packages/magent-flow/src/components/Flow/index.tsx new file mode 100644 index 0000000..7768021 --- /dev/null +++ b/web/packages/magent-flow/src/components/Flow/index.tsx @@ -0,0 +1,168 @@ +import type { Connection, OnSelectionChangeParams } from '@xyflow/react'; +import { Background, ReactFlow } from '@xyflow/react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; + +import type { NodeType } from '@/interfaces/flow'; +import { useFlowStore } from '@/stores/useFlowStore'; +import { useShortcutsStore } from '@/stores/useShortcutsStore'; +import { useUndoRedoStore } from '@/stores/useUndoRedoStore'; +import { getNodeId } from '@/utils/reactflowUtils'; + +import CustomEdge from '../CustomEdge/index.js'; +import { FlowController } from '../FlowController/index.js'; +import '@xyflow/react/dist/style.css'; + +import { + handleCopy, + handleCut, + handleDelete, + handleDuplicate, + handlePaste, + handleRedo, + handleUndo, +} from './keys'; + +const edgeTypes = { + custom: CustomEdge, +}; + +interface FlowProps { + miniMap?: boolean; + classNames?: string; + nodeTypes: any; +} + +function Flow(props: FlowProps) { + const { miniMap = true, classNames, nodeTypes } = props; + const position = useRef({ x: 0, y: 0 }); + const [lastSelection, setLastSelection] = useState( + null, + ); + const reactFlowWrapper = useRef(null); + + const nodes = useFlowStore((state) => state.nodes); + const edges = useFlowStore((state) => state.edges); + const onNodesChange = useFlowStore((state) => state.onNodesChange); + const onEdgesChange = useFlowStore((state) => state.onEdgesChange); + const setNodes = useFlowStore((state) => state.setNodes); + // const setEdges = useFlowStore((state) => state.setEdges); + const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance); + const setReactFlowInstance = useFlowStore((state) => state.setReactFlowInstance); + const deleteNode = useFlowStore((state) => state.deleteNode); + const deleteEdge = useFlowStore((state) => state.deleteEdge); + const onConnect = useFlowStore((state) => state.onConnect); + + const paste = useFlowStore((state) => state.paste); + + const undo = useUndoRedoStore((state) => state.undo); + const redo = useUndoRedoStore((state) => state.redo); + const takeSnapshot = useUndoRedoStore((state) => state.takeSnapshot); + + // Hot keys + const undoAction = useShortcutsStore((state) => state.undo); + const redoAction = useShortcutsStore((state) => state.redo); + const copyAction = useShortcutsStore((state) => state.copy); + const duplicate = useShortcutsStore((state) => state.duplicate); + const deleteAction = useShortcutsStore((state) => state.delete); + const cutAction = useShortcutsStore((state) => state.cut); + const pasteAction = useShortcutsStore((state) => state.paste); + useHotkeys(undoAction, (e) => handleUndo(e, undo)); + useHotkeys(redoAction, (e) => handleRedo(e, redo)); + useHotkeys(duplicate, (e) => handleDuplicate(e, paste, nodes, position)); + useHotkeys(copyAction, (e) => handleCopy(e, lastSelection, setLastSelection)); + useHotkeys(cutAction, (e) => handleCut(e, lastSelection, setLastSelection)); + useHotkeys(pasteAction, (e) => + handlePaste(e, lastSelection, takeSnapshot, paste, position), + ); + useHotkeys(deleteAction, (e) => + handleDelete(e, lastSelection, deleteNode, deleteEdge, takeSnapshot), + ); + useHotkeys('delete', (e) => + handleDelete(e, lastSelection, deleteNode, deleteEdge, takeSnapshot), + ); + + useEffect(() => { + reactFlowInstance?.fitView(); + }, [reactFlowInstance]); + + const onConnectMod = useCallback( + (params: Connection) => { + takeSnapshot(); + onConnect(params); + }, + [takeSnapshot, onConnect], + ); + + const onDrop = useCallback( + (event: React.DragEvent) => { + event.preventDefault(); + if (event.dataTransfer.types.some((types) => types === 'nodedata')) { + takeSnapshot(); + try { + // Extract the data from the drag event and parse it as a JSON object + const data: { type: string; node?: NodeType } = JSON.parse( + event.dataTransfer.getData('nodedata'), + ); + + const newId = getNodeId(data.type); + + const newNode: NodeType = { + id: newId, + type: data.type, + position: { x: 0, y: 0 }, + data: { + ...data.node, + id: newId, + }, + }; + paste( + { nodes: [newNode], edges: [] }, + { x: event.clientX, y: event.clientY }, + ); + } catch (error) {} + } + }, + // Specify dependencies for useCallback + [getNodeId, setNodes, takeSnapshot, paste], + ); + + const onDragOver = useCallback((event: React.DragEvent) => { + event.preventDefault(); + if (event.dataTransfer.types.some((types) => types === 'nodedata')) { + event.dataTransfer.dropEffect = 'move'; + } else { + event.dataTransfer.dropEffect = 'copy'; + } + }, []); + + return ( +
+ + + {miniMap && } + +
+ ); +} + +export default Flow; diff --git a/web/packages/magent-flow/src/components/Flow/keys.ts b/web/packages/magent-flow/src/components/Flow/keys.ts new file mode 100644 index 0000000..b7a0f2b --- /dev/null +++ b/web/packages/magent-flow/src/components/Flow/keys.ts @@ -0,0 +1,116 @@ +import isWrappedWithClass from '@/utils/wrappedClass'; +import { cloneDeep } from 'lodash'; +export function handleUndo(e: KeyboardEvent, undo: any) { + if (!isWrappedWithClass(e, 'noflow')) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); + undo(); + } +} + +export function handleRedo(e: KeyboardEvent, redo: any) { + if (!isWrappedWithClass(e, 'noflow')) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); + redo(); + } +} + +// export function handleGroup(e: KeyboardEvent) { +// if (selectionMenuVisible) { +// e.preventDefault(); +// (e as unknown as Event).stopImmediatePropagation(); +// handleGroupNode(); +// } +// } + +export function handleDuplicate( + e: KeyboardEvent, + paste: any, + nodes: any, + position: any, +) { + e.preventDefault(); + e.stopPropagation(); + (e as unknown as Event).stopImmediatePropagation(); + const selectedNode = nodes.filter((obj) => obj.selected); + if (selectedNode.length > 0) { + paste( + { nodes: selectedNode, edges: [] }, + { + x: position.current.x, + y: position.current.y, + }, + ); + } +} + +export function handleCopy( + e: KeyboardEvent, + lastSelection: any, + setLastCopiedSelection: any, +) { + const multipleSelection = lastSelection?.nodes + ? lastSelection?.nodes.length > 0 + : false; + if ( + !isWrappedWithClass(e, 'noflow') && + (isWrappedWithClass(e, 'react-flow__node') || multipleSelection) + ) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); + if (window.getSelection()?.toString().length === 0 && lastSelection) { + setLastCopiedSelection(cloneDeep(lastSelection)); + } + } +} + +export function handleCut( + e: KeyboardEvent, + lastSelection: any, + setLastCopiedSelection: any, +) { + if (!isWrappedWithClass(e, 'noflow')) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); + if (window.getSelection()?.toString().length === 0 && lastSelection) { + setLastCopiedSelection(cloneDeep(lastSelection), true); + } + } +} + +export function handlePaste( + e: KeyboardEvent, + lastCopiedSelection: any, + takeSnapshot: any, + paste: any, + position: any, +) { + if (!isWrappedWithClass(e, 'noflow')) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); + if (window.getSelection()?.toString().length === 0 && lastCopiedSelection) { + takeSnapshot(); + paste(lastCopiedSelection, { + x: position.current.x, + y: position.current.y, + }); + } + } +} + +export function handleDelete( + e: KeyboardEvent, + lastSelection: any, + deleteNode: any, + deleteEdge: any, + takeSnapshot: any, +) { + if (!isWrappedWithClass(e, 'nodelete') && lastSelection) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); + takeSnapshot(); + deleteNode(lastSelection.nodes.map((node) => node.id)); + deleteEdge(lastSelection.edges.map((edge) => edge.id)); + } +} diff --git a/web/packages/magent-flow/src/components/FlowController/index.tsx b/web/packages/magent-flow/src/components/FlowController/index.tsx new file mode 100644 index 0000000..e5ad6f7 --- /dev/null +++ b/web/packages/magent-flow/src/components/FlowController/index.tsx @@ -0,0 +1,18 @@ +import { Controls, MiniMap } from '@xyflow/react'; +import React from 'react'; + +export const FlowController = () => { + return ( + <> + + + + + ); +}; diff --git a/web/packages/magent-flow/src/components/FlowWithPanel/index.tsx b/web/packages/magent-flow/src/components/FlowWithPanel/index.tsx new file mode 100644 index 0000000..f2b7e3b --- /dev/null +++ b/web/packages/magent-flow/src/components/FlowWithPanel/index.tsx @@ -0,0 +1,242 @@ +import { EventEmitterContextProvider } from '@/context/event-emitter'; +import { NodeDataType, NodeTypeEnum } from '@/interfaces/flow'; +import yaml from 'js-yaml'; +import React from 'react'; +import Flow from '../Flow'; +import { AgentNode } from '../Node/AgentNode'; +import { EndNode } from '../Node/EndNode'; +import { IfElseNode } from '../Node/IfElseNode'; +import { KnowledgeNode } from '../Node/KnowledgeNode'; +import { LLMNode } from '../Node/LLMNode'; +import { StartNode } from '../Node/StartNode'; +import { NodesPanel } from '../NodePanel'; + +const yamlContent = ` +- id: 1 + name: 开始节点 + description: 工作流的起始节点,用于设定启动工作流需要的信息 + type: start + position: + x: 100 + y: 100 + data: + outputs: + - name: user_input + type: string + description: 用户本轮对话输入内容 +- id: 2 + position: + x: 200 + y: 100 + name: 结束节点 + description: 工作流的最终节点,用于返回工作流运行后的结果信息 + type: end + data: + inputs: + input_param: + - name: response + type: string + value: + type: reference + content: ['llm1', 'output'] # 通过nodeId + paramKey 定位引用变量 + prompt: + name: response + type: string + description: 输出内容 + value: '{{response}}' +- id: 3 + name: 大模型节点 + description: 调用大语言模型,使用变量和提示词生成回复 + type: llm + position: + x: 300 + y: 100 + data: + inputs: + input_param: + - name: input + description: + type: string + value: + type: reference + - name: background + description: + type: string + value: + type: reference + llm_param: + - type: string + name: id + value: qwen_llm + - type: string + name: model_name + value: qwen-max + - type: string + name: temperature + value: '0.7' + - type: string + name: prompt + value: | + 你是一位精通信息分析的ai助手。你的目标是使用中文结合查询的背景信息及你所拥有的知识回答用户提出的问题。 + 你需要遵守的规则是: + 1. 必须使用中文结合查询的背景信息结合你所拥有的知识回答用户提出的问题。 + 2. 结构化答案生成,必要时通过空行提升阅读体验。 + 3. 不采用背景信息中的错误信息。 + 4. 要考虑答案和问题的相关性,不做对问题没有帮助的回答。 + 5. 详尽回答问题,重点突出,不过多花哨词藻。 + 6. 不说模糊的推测。 + 7. 尽量多的使用数值类信息。 + + 背景信息是: + {background} + + 开始! + 需要回答的问题是: {input} + outputs: + - type: string + name: output +- id: 4 + name: 知识库示例 + description: + type: knowledge + position: + x: 400 + y: 100 + data: + inputs: + knowledge_param: + - type: string + name: id + value: demo_knowledge + - type: string + name: top_k + value: + type: value + content: '2' + input_param: + - type: string + name: query # 自然语言的知识库query + value: + type: reference + outputs: + - name: output + type: string +- id: 5 + name: 谷歌搜索工具 + description: + type: tool + position: + x: 500 + y: 100 + data: + inputs: + tool_param: + - type: string + name: id + value: google_search + input_param: + - type: string + name: input + value: + type: value + content: 'output' # 通过nodeId + paramKey 定位引用变量 + outputs: + - name: output + type: string +- id: 6 + name: rag智能体 + description: + type: agent + position: + x: 600 + y: 100 + data: + inputs: + agent_param: + - type: string + name: id + value: demo_rag_agent + input_param: + - type: string + name: input + value: + type: reference + + outputs: + - name: output + type: string +- id: 7 + name: 条件判断 + description: + type: ifelse + position: + x: 700 + y: 100 + data: + inputs: + branches: # 这一期这做一层,不包括 and or 还有我理解默认逻辑不展示在这块对吧,只在edge体现 + - name: branch-1 + conditions: + - compare: equal + left: + type: string + value: + type: reference + right: # blank 没有right + type: string # 只有 if 和 else,branch-1和branch-default + value: + type: reference + + +`; + +export const NodeSchemaParser = (obj: Record) => { + obj.config = obj.data; + obj.icon = + 'https://mdn.alipayobjects.com/huamei_xbkogb/afts/img/A*PzmdRpvZz58AAAAAAAAAAAAADqarAQ/original'; + + delete obj.data; +}; + +const nodeTypes = { + [NodeTypeEnum.Start]: StartNode, + [NodeTypeEnum.End]: EndNode, + [NodeTypeEnum.LLM]: LLMNode, + [NodeTypeEnum.Knowledge]: KnowledgeNode, + [NodeTypeEnum.IfElse]: IfElseNode, + [NodeTypeEnum.Tool]: IfElseNode, + [NodeTypeEnum.Agent]: AgentNode, +}; + +export const FlowWithPanel = () => { + const yaml_data = yaml.load(yamlContent); + (yaml_data as Record[]).forEach((item) => { + NodeSchemaParser(item); + }); + console.log('🚀 ~ yaml_data:', yaml_data); + + // const setNodes = useFlowStore((state) => state.setNodes); + // const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance); + + // useEffect(() => { + // const add = (yaml_data as any).map((node: any) => { + // return { + // id: node.id, + // type: node.type, + // position: node.position, + // data: node, + // }; + // }); + + // setNodes(add); + // }, [reactFlowInstance]); + + return ( + +
+ + +
+
+ ); +}; diff --git a/web/packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml b/web/packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml new file mode 100644 index 0000000..c947a3b --- /dev/null +++ b/web/packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml @@ -0,0 +1,171 @@ +- id: 1 + name: 开始节点 + description: 工作流的起始节点,用于设定启动工作流需要的信息 + type: start + data: + outputs: + - name: user_input + type: string + description: 用户本轮对话输入内容 +- id: 2 + name: 结束节点 + description: 工作流的最终节点,用于返回工作流运行后的结果信息 + type: end + data: + inputs: + input_param: + - name: response + type: string + value: + type: reference + content: ['llm1', 'output'] # 通过nodeId + paramKey 定位引用变量 + prompt: + name: response + type: string + description: 输出内容 + value: '{{response}}' +- id: 3 + name: 大模型节点 + description: 调用大语言模型,使用变量和提示词生成回复 + type: llm + position: + x: 1 + y: 2 + data: + inputs: + input_param: + - name: input + description: + type: string + value: + type: reference + content: ['start', 'BOT_USER_INPUT'] + - name: background + description: + type: string + value: + type: reference + content: ['someNode', 'variable2'] + llm_param: + - type: string + name: id + value: qwen_llm + - type: string + name: model_name + value: qwen-max + - type: string + name: temperature + value: '0.7' + - type: string + name: prompt + value: | + 你是一位精通信息分析的ai助手。你的目标是使用中文结合查询的背景信息及你所拥有的知识回答用户提出的问题。 + 你需要遵守的规则是: + 1. 必须使用中文结合查询的背景信息结合你所拥有的知识回答用户提出的问题。 + 2. 结构化答案生成,必要时通过空行提升阅读体验。 + 3. 不采用背景信息中的错误信息。 + 4. 要考虑答案和问题的相关性,不做对问题没有帮助的回答。 + 5. 详尽回答问题,重点突出,不过多花哨词藻。 + 6. 不说模糊的推测。 + 7. 尽量多的使用数值类信息。 + + 背景信息是: + {background} + + 开始! + 需要回答的问题是: {input} + outputs: + - type: string + - name: output +- id: 4 + name: 知识库示例 + description: + type: knowledge + position: + x: 1 + y: 2 + data: + inputs: + knowledge_param: + - type: string + name: id + value: demo_knowledge + - type: string + name: top_k + value: '2' + input_param: + - type: string + name: query # 自然语言的知识库query + value: + type: reference + content: ['1', 'output'] # 通过nodeId + paramKey 定位引用变量 + outputs: + - name: output + type: string +- id: 5 + name: 谷歌搜索工具 + description: + type: tool + position: + x: 1 + y: 2 + data: + inputs: + tool_param: + - type: string + name: id + value: google_search + input_param: + - type: string + name: input + value: + type: value + content: 'output' # 通过nodeId + paramKey 定位引用变量 + outputs: + - name: output + type: string +- id: 4 + name: rag智能体 + description: + type: agent + position: + x: 1 + y: 2 + data: + inputs: + agent_param: + - type: string + name: id + value: demo_rag_agent + input_param: + - type: string + name: input + value: + type: reference + content: ['1', 'output'] # 通过nodeId + paramKey 定位引用变量 + outputs: + - name: output + type: string +- id: 7 + name: 条件判断 + description: + type: ifelse + position: + x: 1 + y: 2 + data: + inputs: + branches: # 这一期这做一层,不包括 and or 还有我理解默认逻辑不展示在这块对吧,只在edge体现 + - name: branch-1 + conditions: + - compare: equal/not-equal/blank + left: + type: string + value: + type: reference + content: ['1', 'output'] + right: # blank 没有right + type: string # 只有 if 和 else,branch-1和branch-default + value: + type: reference + content: ['2', 'output'] diff --git a/web/packages/magent-flow/src/components/Node/AgentNode/index.tsx b/web/packages/magent-flow/src/components/Node/AgentNode/index.tsx new file mode 100644 index 0000000..5e25a3f --- /dev/null +++ b/web/packages/magent-flow/src/components/Node/AgentNode/index.tsx @@ -0,0 +1,53 @@ +import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper'; +import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable'; +import { ReferenceForm } from '@/components/ReferenceForm'; +import { NodeDataType } from '@/interfaces/flow'; +import { useFlowStore } from '@/stores/useFlowStore'; +import React from 'react'; +import { NodeWrapper } from '../NodeWrapper'; + +type Props = { + data: NodeDataType; + selected: boolean; + xPos: number; + yPos: number; +}; + +export const AgentNode = (props: Props) => { + const { data } = props; + // const { config } = data; + const { findUpstreamNodes } = useFlowStore(); + const upstreamNodes = findUpstreamNodes(data.id.toString()); + console.log('🚀 ~ AgentNode ~ upstreamNodes:', upstreamNodes); + + return ( + +
+ { + console.log('ReferenceForm', values); + }} + /> + + + {(data.config?.outputs || []).map((output) => ( + + ))} + + } + /> +
+
+ ); +}; diff --git a/web/packages/magent-flow/src/components/Node/CommonNode/index.tsx b/web/packages/magent-flow/src/components/Node/CommonNode/index.tsx new file mode 100644 index 0000000..6377ffc --- /dev/null +++ b/web/packages/magent-flow/src/components/Node/CommonNode/index.tsx @@ -0,0 +1,34 @@ +import { NodeDataType } from '@/interfaces/flow'; +import { Collapse } from 'antd'; +import React from 'react'; +import { NodeWrapper } from '../NodeWrapper'; + +type Props = { + data: NodeDataType; + selected: boolean; + xPos: number; + yPos: number; +}; + +export const CommonNode = (props: Props) => { + const { data } = props; + const { config } = data; + + return ( + + <> + {config?.inputs && config?.inputs.length > 0 && ( + {111}

, + }, + ]} + /> + )} + +
+ ); +}; diff --git a/web/packages/magent-flow/src/components/Node/EndNode/index.tsx b/web/packages/magent-flow/src/components/Node/EndNode/index.tsx new file mode 100644 index 0000000..8b3cf8f --- /dev/null +++ b/web/packages/magent-flow/src/components/Node/EndNode/index.tsx @@ -0,0 +1,34 @@ +import { ReferenceForm } from '@/components/ReferenceForm'; +import { NodeDataType } from '@/interfaces/flow'; +import { useFlowStore } from '@/stores/useFlowStore'; +import { Collapse } from 'antd'; +import React from 'react'; +import { NodeWrapper } from '../NodeWrapper'; + +type Props = { + data: NodeDataType; + selected: boolean; + xPos: number; + yPos: number; +}; + +export const EndNode = (props: Props) => { + const { data } = props; + const { findUpstreamNodes } = useFlowStore(); + const upstreamNode = findUpstreamNodes(data.id.toString()); + + return ( + + + { + console.log('ReferenceForm', values); + }} + /> + + + ); +}; diff --git a/web/packages/magent-flow/src/components/Node/IfElseNode/index.tsx b/web/packages/magent-flow/src/components/Node/IfElseNode/index.tsx new file mode 100644 index 0000000..e9c3924 --- /dev/null +++ b/web/packages/magent-flow/src/components/Node/IfElseNode/index.tsx @@ -0,0 +1,76 @@ +import { SelectInNode } from '@/components/AIBasic/SelectInNode'; +import { ReferenceSelect } from '@/components/ReferenceSelect'; +import { NodeDataType } from '@/interfaces/flow'; +import { useFlowStore } from '@/stores/useFlowStore'; +import { Form } from 'antd'; +import React from 'react'; +import { NodeWrapper } from '../NodeWrapper'; + +type Props = { + data: NodeDataType; + selected: boolean; + xPos: number; + yPos: number; +}; + +export const IfElseNode = (props: Props) => { + const { data } = props; + const [form] = Form.useForm(); + const compare = Form.useWatch('compare', form); + const { findUpstreamNodes } = useFlowStore(); + const upstreamNode = findUpstreamNodes(data.id.toString()); + const options = upstreamNode.map((node) => { + return { + label: node.data.name, + value: node.data.id, + children: + node.data?.config?.outputs?.map((output) => { + return { + label: output.name, + value: output.name, + }; + }) || [], + }; + }); + return ( + + <> +
+
+
如果
+
+ + + + + + + {compare !== 'blank' && ( + + + + )} +
+
+
+
+
否则
+
+ +
+ ); +}; diff --git a/web/packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx b/web/packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx new file mode 100644 index 0000000..8a9a027 --- /dev/null +++ b/web/packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx @@ -0,0 +1,84 @@ +import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper'; +import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable'; +import { ReferenceForm } from '@/components/ReferenceForm'; +import { NodeDataType } from '@/interfaces/flow'; +import { useFlowStore } from '@/stores/useFlowStore'; +import { useKnowledgeStore } from '@/stores/useKnowledgeStore'; +import { PlusOutlined } from '@ant-design/icons'; +import { Button, Modal } from 'antd'; +import React from 'react'; +import { NodeWrapper } from '../NodeWrapper'; + +type Props = { + data: NodeDataType; + selected: boolean; + xPos: number; + yPos: number; +}; + +export const KnowledgeNode = (props: Props) => { + const { data } = props; + // const { config } = data; + const { findUpstreamNodes } = useFlowStore(); + + const { knowledges } = useKnowledgeStore(); + const upstreamNode = findUpstreamNodes(data.id.toString()); + + return ( + +
+ { + console.log('ReferenceForm', values); + }} + /> + +
知识库配置
+ +
+ } + content={<>List} + /> + + {(data.config?.outputs || []).map((output) => ( + + ))} + + } + /> + +
+ ); +}; diff --git a/web/packages/magent-flow/src/components/Node/LLMNode/index.tsx b/web/packages/magent-flow/src/components/Node/LLMNode/index.tsx new file mode 100644 index 0000000..f736768 --- /dev/null +++ b/web/packages/magent-flow/src/components/Node/LLMNode/index.tsx @@ -0,0 +1,120 @@ +import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper'; +import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable'; +import PromptEditor from '@/components/AIBasic/PromptEditor'; +import { SelectInNode } from '@/components/AIBasic/SelectInNode'; +import { ReferenceForm } from '@/components/ReferenceForm'; +import { NodeDataType } from '@/interfaces/flow'; +import { useFlowStore } from '@/stores/useFlowStore'; +import { useModelStore } from '@/stores/useModelStore'; +import { BarsOutlined } from '@ant-design/icons'; +import { Button, InputNumber, Popover } from 'antd'; +import React, { useState } from 'react'; +import { NodeWrapper } from '../NodeWrapper'; + +type Props = { + data: NodeDataType; + selected: boolean; + xPos: number; + yPos: number; +}; + +export const LLMNode = (props: Props) => { + const { data } = props; + // console.log('🚀 ~ LLMNode ~ data:', data); + // const { config } = data; + + const { findUpstreamNodes } = useFlowStore(); + const upstreamNode = findUpstreamNodes(data.id.toString()); + + const { models, modelConfig } = useModelStore(); + + const [value, setValue] = useState('hello'); + return ( + +
+ {/* Part1 model selector & model config */} + + ({ + label: model.name, + value: model.id, + }))} + className="w-full mr-2" + /> + + {Object.entries(modelConfig).map(([key, value]) => ( + <> + {key} + + ))} +
+ } + > + {Object.entries(modelConfig).length > 0 && ( + + )} + + + } + /> + {/* Part2 Ref Form */} + + { + console.log('ReferenceForm', values); + }} + /> + {/* Part3 PromptEditor */} + + setValue(val)} + variableBlock={{ + show: true, + variables: data.config?.inputs?.input_param.map((input) => { + return { + name: input.name!, + value: input.name!, + }; + }), + }} + /> + + } + /> + {/* Part4 Outputer */} + + {(data.config?.outputs || []).map((output) => ( + + ))} + + } + /> + +
+ ); +}; diff --git a/web/packages/magent-flow/src/components/Node/NodeWrapper/Header/index.tsx b/web/packages/magent-flow/src/components/Node/NodeWrapper/Header/index.tsx new file mode 100644 index 0000000..41c7f5a --- /dev/null +++ b/web/packages/magent-flow/src/components/Node/NodeWrapper/Header/index.tsx @@ -0,0 +1,18 @@ +import { EllipsisOutlined, PlayCircleFilled } from '@ant-design/icons'; +import React from 'react'; + +export const NodeHeader = (props: { icon: React.JSX.Element; name: string }) => { + const { icon, name } = props; + return ( +
+
+ {icon} +
{name}
+
+
+ + +
+
+ ); +}; diff --git a/web/packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx b/web/packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx new file mode 100644 index 0000000..e85322e --- /dev/null +++ b/web/packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx @@ -0,0 +1,73 @@ +import { classNames } from '@/utils/basic'; +import { Popover, Tag } from 'antd'; +import React from 'react'; + +export enum RunStatusEnum { + Success = 'success', + Processing = 'processing', + Warning = 'warning', + Error = 'error', +} + +export const RunStatusMap = { + [RunStatusEnum.Success]: { + Label: '运行成功', + Color: 'green', + Cssclsname: 'bg-green-50', + }, + [RunStatusEnum.Processing]: { + Label: '运行中', + Color: 'blue', + Cssclsname: 'bg-blue-50', + }, + [RunStatusEnum.Warning]: { + Label: '警告', + Color: 'yellow', + Cssclsname: 'bg-yellow-50', + }, + [RunStatusEnum.Error]: { + Label: '运行失败', + Color: 'red', + Cssclsname: 'bg-red-50', + }, +}; + +export interface RunResStatus { + status: RunStatusEnum; + runDuration: number; + runInput?: Record; + runOutput?: Record; +} + +export const NodeStatus = (props: RunResStatus) => { + const { status, runDuration } = props; + + const StatusInfo = RunStatusMap[status]; + return ( +
+
+ {StatusInfo.Label} + + {`${runDuration}s`} +
+ +
输入:
+
输出:
+ + } + > + 运行结果 +
+
+ ); +}; diff --git a/web/packages/magent-flow/src/components/Node/NodeWrapper/index.tsx b/web/packages/magent-flow/src/components/Node/NodeWrapper/index.tsx new file mode 100644 index 0000000..2d6381b --- /dev/null +++ b/web/packages/magent-flow/src/components/Node/NodeWrapper/index.tsx @@ -0,0 +1,91 @@ +import { Handle, Position } from '@xyflow/react'; +import { Space } from 'antd'; +import React from 'react'; + +import type { NodeDataType } from '@/interfaces/flow'; +import { classNames } from '@/utils'; + +type Props = { + data: NodeDataType; + selected: boolean; + xPos: number; + yPos: number; +}; + +export const NodeWrapper = (props: { + nodeProps: Props; + children: React.ReactElement; + leftHandler?: boolean; + rightHandler?: boolean; + rightHandlerConfig?: { + id: string; + style: Record; + }[]; +}) => { + const { + nodeProps, + children, + leftHandler = true, + rightHandler = true, + rightHandlerConfig, + } = props; + const { name, description, icon } = nodeProps.data; + console.log('🚀 ~ nodeProps.selected:', nodeProps.selected); + // const runRes = {}; + // const validationStatus = true; + + return ( +
+ {/* */} +
+ + {icon && } +
{name}
+
+
+ {leftHandler && ( + + )} + {rightHandler && + (rightHandlerConfig ? ( + <> + {rightHandlerConfig.map((item) => ( + + ))} + + ) : ( + + ))} + +
+
{description}
+
+
{children}
+
+ ); +}; diff --git a/web/packages/magent-flow/src/components/Node/StartNode/index.tsx b/web/packages/magent-flow/src/components/Node/StartNode/index.tsx new file mode 100644 index 0000000..555da9c --- /dev/null +++ b/web/packages/magent-flow/src/components/Node/StartNode/index.tsx @@ -0,0 +1,34 @@ +import { VariableForm } from '@/components/VariableForm'; +import { NodeDataType } from '@/interfaces/flow'; +import { Collapse } from 'antd'; +import React from 'react'; +import { NodeWrapper } from '../NodeWrapper'; + +type Props = { + data: NodeDataType; + selected: boolean; + xPos: number; + yPos: number; +}; + +export const StartNode = (props: Props) => { + const { data } = props; + + return ( + + + {/* */} + + { + console.log('qianyan', values); + }} + /> + + + ); +}; diff --git a/web/packages/magent-flow/src/components/Node/index.tsx b/web/packages/magent-flow/src/components/Node/index.tsx new file mode 100644 index 0000000..e69de29 diff --git a/web/packages/magent-flow/src/components/NodePanel/index.tsx b/web/packages/magent-flow/src/components/NodePanel/index.tsx new file mode 100644 index 0000000..d97e01b --- /dev/null +++ b/web/packages/magent-flow/src/components/NodePanel/index.tsx @@ -0,0 +1,70 @@ +import { NodeDataType } from '@/interfaces/flow'; +import { Input } from 'antd'; +import React from 'react'; + +interface NodesPanelProps { + /** + * @title 模板节点配置 + */ + className?: string; + nodes: NodeDataType[]; + // allowfold?: boolean; + allowSearch?: boolean; + // grouped?: boolean; +} + +export const NodesPanel = (props: NodesPanelProps) => { + const { nodes, allowSearch = false, className = '' } = props; + + function onDragStart( + event: React.DragEvent, + data: { type: string; node?: NodeDataType }, + ): void { + //start drag event + // eslint-disable-next-line no-var + var crt = event.currentTarget.cloneNode(true); + + crt.style.position = 'absolute'; + crt.style.top = '-500px'; + crt.style.right = '-500px'; + crt.classList.add('cursor-grabbing'); + document.body.appendChild(crt); + event.dataTransfer.setDragImage(crt, 0, 0); + event.dataTransfer.setData('nodedata', JSON.stringify(data)); + } + + return ( +
+ {allowSearch && ( + { + nodes.filter((node) => node.name.includes(e.target.value)); + }} + /> + )} + {nodes.sort().map((node) => ( +
+ onDragStart(event, { + type: node.type, + node: node, + }) + } + onDragEnd={() => { + document.body.removeChild( + document.getElementsByClassName('cursor-grabbing')[0], + ); + }} + > + {node.icon && } +
{node.name}
+
+ ))} + <> +
+ ); +}; diff --git a/web/packages/magent-flow/src/components/RefForm/index.md b/web/packages/magent-flow/src/components/RefForm/index.md new file mode 100644 index 0000000..5be9d1e --- /dev/null +++ b/web/packages/magent-flow/src/components/RefForm/index.md @@ -0,0 +1,31 @@ +--- +title: RefForm +group: { title: 'Schema', order: 2 } +toc: menu +order: 1 +demo: { cols: 2 } +--- + +## 基本用法 + +> 渲染输入参数表单,支持传入节点引用数据 + +```jsx +import React from 'react'; +import { RefForm, FormSchema, StartNode } from '@alipay/ai-workflow'; + +const startNode = new StartNode(); +startNode.input.updateSchema({ + type: 'object', + properties: { + name: { + type: 'string', + title: '姓名', + }, + }, +}); + +export default () => Hi, bigfish; +``` + + diff --git a/web/packages/magent-flow/src/components/ReferenceForm/index.tsx b/web/packages/magent-flow/src/components/ReferenceForm/index.tsx new file mode 100644 index 0000000..e68591f --- /dev/null +++ b/web/packages/magent-flow/src/components/ReferenceForm/index.tsx @@ -0,0 +1,117 @@ +import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; +import { Button, Form, Input, Space } from 'antd'; +import React, { useEffect } from 'react'; + +import type { BasicSchema, NodeType } from '@/interfaces/flow'; + +import { CollapseWrapper } from '../AIBasic/CollapseWrapper'; +import { ReferenceSelect } from '../ReferenceSelect'; + +export interface RefrenceFormProps { + label: string; + values: BasicSchema[]; + onChange: (values: []) => void; + nodes: NodeType[]; + dynamic?: boolean; +} + +export const ReferenceForm = (props: RefrenceFormProps) => { + const { label, values, onChange, nodes, dynamic = false } = props; + + const [form] = Form.useForm(); + + useEffect(() => { + form.setFieldValue('variables', values); + }, []); + console.log('🚀 ~ useEffect ~ values:', values); + + const options = nodes.map((node) => { + return { + label: node.data.name, + value: node.data.id, + children: node.data?.config?.outputs?.map((output) => { + return { + label: output.name, + value: output.name, + }; + }), + }; + }); + + return ( + { + console.log('🚀 ~ form.validateFields ~ allFields:', allFields); + form.validateFields().then(() => { + if (allFields.variables) { + onChange(allFields.variables.filter((item: any) => item !== undefined)); + } + }); + }} + > +
+ + {() => ( + <> + + 参数名 + 变量值 + + + )} + +
+ + {(fields, { add, remove }) => ( + <> + {fields.map(({ key, name, ...restField }) => ( + + + + + + + + + {dynamic && ( + remove(name)} + /> + )} + + ))} + {dynamic && ( + + + + )} + + )} + + + } + /> + ); +}; diff --git a/web/packages/magent-flow/src/components/ReferenceSelect/index.tsx b/web/packages/magent-flow/src/components/ReferenceSelect/index.tsx new file mode 100644 index 0000000..04c1991 --- /dev/null +++ b/web/packages/magent-flow/src/components/ReferenceSelect/index.tsx @@ -0,0 +1,61 @@ +import { Input } from 'antd'; +import React from 'react'; +import { CascaderInNode } from '../AIBasic/CascaderInNode'; +import { SelectInNode } from '../AIBasic/SelectInNode'; + +export const ReferenceSelect = (props: { + value?: { + type: 'reference' | 'value'; + content?: string | [string, string]; + }; + onChange?: (value: { + type: 'reference' | 'value'; + content?: string | [string, string]; + }) => void; + refOptions: { label: string; content: string }[]; +}) => { + const { value, onChange, refOptions } = props; + console.log('🚀 ~ value:', value); + + return ( +
+ + onChange?.({ + type: val, + }) + } + options={[ + { label: '引用', value: 'reference' }, + { label: '值', value: 'value' }, + ]} + /> + + {value?.type === 'value' ? ( + + onChange?.({ + type: value.type, + content: e.target.value, + }) + } + /> + ) : ( + + onChange?.({ + type: value?.type, + content: val, + }) + } + options={refOptions} + /> + )} +
+ ); +}; diff --git a/web/packages/magent-flow/src/components/VariableForm/index.tsx b/web/packages/magent-flow/src/components/VariableForm/index.tsx new file mode 100644 index 0000000..94a783e --- /dev/null +++ b/web/packages/magent-flow/src/components/VariableForm/index.tsx @@ -0,0 +1,148 @@ +import { + CaretRightOutlined, + MinusCircleOutlined, + PlusOutlined, +} from '@ant-design/icons'; +import { Button, Checkbox, Collapse, Form, Input, Space } from 'antd'; +import React, { useEffect } from 'react'; + +import type { BasicSchema } from '@/interfaces/flow'; + +import { SelectInNode } from '../AIBasic/SelectInNode'; + +export interface VariableFormProps { + label: string; + values: BasicSchema[]; + onChange: (values: BasicSchema[]) => void; + dynamic?: boolean; + showRequired?: boolean; +} + +export const VariableForm = (props: VariableFormProps) => { + const { label, values, onChange, dynamic = true, showRequired = true } = props; + const onFinish = (values: any) => { + console.log('Received values of form:', values); + }; + const [form] = Form.useForm(); + + useEffect(() => { + form.setFieldValue('variables', values); + }, []); + + return ( + } + items={[ + { + key: '1', + label: label, + children: ( +
{ + form.validateFields().then(() => { + if (allFields.variables) { + onChange( + allFields.variables.filter((item: any) => item !== undefined), + ); + } + }); + }} + > +
+ + {() => ( + <> + + 变量名 + 变量类型 + {/* 变量描述 */} + {showRequired && ( + 是否必要 + )} + + + )} + +
+ + {(fields, { add, remove }) => ( + <> + {fields.map(({ key, name, ...restField }) => ( + + + + + + ', + value: 'Array', + }, + ]} + placeholder="" + /> + + {/* + + */} + {showRequired && ( + + + + )} + {dynamic && ( + remove(name)} + /> + )} + + ))} + {dynamic && ( + + + + )} + + )} + +
+ ), + }, + ]} + /> + ); +}; diff --git a/web/packages/magent-flow/src/constants/constant.ts b/web/packages/magent-flow/src/constants/constant.ts new file mode 100644 index 0000000..2f67d19 --- /dev/null +++ b/web/packages/magent-flow/src/constants/constant.ts @@ -0,0 +1,96 @@ +export const IS_MAC = navigator.userAgent.toUpperCase().includes('MAC'); + +export const defaultShortcuts = [ + { + name: 'Advanced Settings', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + Shift + A`, + }, + { + name: 'Minimize', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + Q`, + }, + { + name: 'Code', + shortcut: `Space`, + }, + { + name: 'Copy', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + C`, + }, + { + name: 'Duplicate', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + D`, + }, + { + name: 'Component Share', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + Shift + S`, + }, + { + name: 'Docs', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + Shift + D`, + }, + { + name: 'Save', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + S`, + }, + { + name: 'Delete', + shortcut: 'Backspace', + }, + { + name: 'Open playground', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + K`, + }, + { + name: 'Undo', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + Z`, + }, + { + name: 'Redo', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + Y`, + }, + { + name: 'Group', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + G`, + }, + { + name: 'Cut', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + X`, + }, + { + name: 'Paste', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + V`, + }, + { + name: 'API', + shortcut: `R`, + }, + { + name: 'Download', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + J`, + }, + { + name: 'Update', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + U`, + }, + { + name: 'Freeze', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + F`, + }, + { + name: 'Freeze Path', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + Shift + F`, + }, + { + name: 'Flow Share', + shortcut: `${IS_MAC ? 'Cmd' : 'Ctrl'} + B`, + }, + { + name: 'Play', + shortcut: `P`, + }, + { + name: 'Output Inspection', + shortcut: `O`, + }, +]; diff --git a/web/packages/magent-flow/src/context/event-emitter.tsx b/web/packages/magent-flow/src/context/event-emitter.tsx new file mode 100644 index 0000000..9ac57dc --- /dev/null +++ b/web/packages/magent-flow/src/context/event-emitter.tsx @@ -0,0 +1,30 @@ +'use client'; +import { useEventEmitter } from 'ahooks'; +import type { EventEmitter } from 'ahooks/lib/useEventEmitter'; +import React, { createContext, useContext } from 'react'; +// import { createContext, useContext } from 'use-context-selector'; + +const EventEmitterContext = createContext<{ + eventEmitter: EventEmitter | null; +}>({ + eventEmitter: null, +}); + +export const useEventEmitterContextContext = () => useContext(EventEmitterContext); + +type EventEmitterContextProviderProps = { + children: React.ReactNode; +}; +export const EventEmitterContextProvider = ({ + children, +}: EventEmitterContextProviderProps) => { + const eventEmitter = useEventEmitter(); + + return ( + + {children} + + ); +}; + +export default EventEmitterContext; diff --git a/web/packages/magent-flow/src/index.ts b/web/packages/magent-flow/src/index.ts new file mode 100644 index 0000000..dc5c313 --- /dev/null +++ b/web/packages/magent-flow/src/index.ts @@ -0,0 +1,8 @@ +export { default as Flow } from './components/Flow'; +export { FlowWithPanel } from './components/FlowWithPanel'; +export { FormSchema } from './FormSchema'; +export { RefForm } from './RefForm'; +export { SchemaConfigForm } from './SchemaConfigForm'; +export { StartNode } from './spec/node'; +export * from './utils/index.js'; +import './tailwind.out.css'; diff --git a/web/packages/magent-flow/src/interfaces/flow.ts b/web/packages/magent-flow/src/interfaces/flow.ts new file mode 100644 index 0000000..c6e1f96 --- /dev/null +++ b/web/packages/magent-flow/src/interfaces/flow.ts @@ -0,0 +1,108 @@ +import { ReactFlowJsonObject, XYPosition } from '@xyflow/react'; + +export enum NodeTypeEnum { + 'Start' = 'start', + 'End' = 'end', + 'LLM' = 'llm', + 'Knowledge' = 'knowledge', + 'Agent' = 'agent', + + // 'Plugin' = 'plugin', + 'Tool' = 'tool', + 'IfElse' = 'ifelse', +} + +export enum IfElseNodeCompareType { + Equal = 'equal', + NotEqual = 'notequal', + Blank = 'blank', +} + +export interface LiteralValueType { + type: 'value'; + content?: string | number | boolean | string[] | number[] | boolean[]; +} + +export interface RefValueType { + type: 'reference'; + content?: { + source: string; + blockID: string; + name: string; + }; +} + +export interface BasicSchema { + type: string; + name?: string; + value?: LiteralValueType | RefValueType; + required?: boolean; + // BasicSchema 对应 type = list,BasicSchema[] 对应 type = object + schema?: BasicSchema | BasicSchema[]; + description?: string; +} + +export interface NodeDataConfigType { + inputs?: { + input_param: BasicSchema[]; + [key: string]: BasicSchema[]; + }; + outputs?: BasicSchema[]; +} + +// export interface NodeDataMetaType { +// name: string; +// icon?: string; +// description?: string; +// } + +export interface NodeDataType { + id: string | number; + type: NodeTypeEnum; + runResult?: { + status: string; + result?: any; + }; + name: string; + icon?: string; + description?: string; + config?: NodeDataConfigType; +} + +export interface NodeType { + id: string; + position: XYPosition; + type: string; + data: NodeDataType; + selected?: boolean; +} + +export type FlowType = { + id: string; + name: string; + icon?: string; + description: string; + data: ReactFlowJsonObject | null; + // + updated_at?: string; + date_created?: string; + user_id?: string; +}; + +// right side +export type sourceHandleType = { + dataType: string; + id: string; + output_types: string[]; + conditionalPath?: string | null; + name: string; +}; + +//left side +export type targetHandleType = { + inputTypes?: string[]; + type: string; + fieldName: string; + id: string; + proxy?: { field: string; id: string }; +}; diff --git a/web/packages/magent-flow/src/spec/FormSchema/index.ts b/web/packages/magent-flow/src/spec/FormSchema/index.ts new file mode 100644 index 0000000..3bc0582 --- /dev/null +++ b/web/packages/magent-flow/src/spec/FormSchema/index.ts @@ -0,0 +1,328 @@ +import { message } from 'antd'; +import type { + JSONSchema7, + JSONSchema7Definition, + JSONSchema7TypeName, +} from 'json-schema'; + +import { UUID } from '../uuid.js'; + +export type OrderJSONSchema7 = JSONSchema7 & { + order: number; +}; + +export interface CascaderOptions { + value: string; + label: string; + children?: CascaderOptions[]; +} + +/** + * 声明输入的表单数据格式 + * 表单内容 + */ +export class FormSchema { + uuid = UUID.getInstance().uniqueID(); + + jsonschema: JSONSchema7 = { + $id: this.uuid, + type: 'object', + properties: {}, + required: [], + }; + + /** + * 获取指定路径的属性 + * 方便添加属性 + * /a/b/c/ + * @param pointer + * @returns + */ + getSchemaByPoint(pointer: string) { + if (pointer === '/' || pointer === '') { + return this.jsonschema; + } + + let pointers = pointer.split('/'); + if (pointers[0] !== '') { + throw new Error('invalid pointer'); + } + pointers = pointers.slice(1); + + // base是一个object模式 + let schema = this.jsonschema; + while (pointers.length > 0) { + const pointer = pointers.shift(); + if (pointer === undefined) { + throw new Error('invalid pointer'); + } + if (schema) { + if (schema.type === 'object') { + if (schema?.properties?.[pointer]) { + // 有就递归下沉 + schema = schema.properties[pointer] as JSONSchema7; + } else { + // 没有属性就添加 + schema!.properties![pointer] = {}; + return schema!.properties![pointer]; + } + } else if (schema?.type === 'array') { + if (schema?.items) { + const index = parseInt(pointer); + if (Array.isArray(schema.items)) { + schema = schema.items[index] as JSONSchema7; + } else { + schema = schema.items as JSONSchema7; + } + } + } + } + } + return schema; + } + + private randommName = () => { + return ( + 'RandaomName__-' + + Math.random().toString(36).substring(2, 15) + + Math.random().toString(36).substring(2, 15) + ); + }; + + isRandomName = (name: string) => { + return name.startsWith('RandaomName__-'); + }; + + /** + * 动态表单添加属性 + * @param property + * @returns + */ + addField = (options: { + pointer: string; // 指定属性路径,如 /a/b + name?: string; + type: JSONSchema7TypeName; + description: string; + required: boolean; + }) => { + const { pointer, name = this.randommName(), type, description, required } = options; + if (typeof this.jsonschema !== 'boolean') { + const schema = this.getSchemaByPoint(pointer); + if (schema.type === 'array') { + // 如果存在属性 + if (!schema?.items) { + schema.items = { + type: type, + description, + }; + } else if (!Array.isArray(schema?.items)) { + const items = schema.items as JSONSchema7Definition; + schema.items = [ + items, + { + type: type, + description, + }, + ]; + } else if (Array.isArray(schema?.items)) { + schema.items.push({ + type: type, + description, + }); + } + } else if (schema?.type === 'object') { + // 使用order 记录顺序 + let order = 0; + Object.entries(schema.properties || {}).forEach(([, val]) => { + const v = val as OrderJSONSchema7; + if (v?.order) { + order = v?.order > order ? v?.order : order; + } + }); + + (schema.properties![name] as OrderJSONSchema7) = { + type: type, + description, + order: order + 1, + }; + if (type === 'object') { + schema.properties![name].properties = {}; + } + } else { + schema.type = type; + schema.description = description; + } + if (required) { + // 如果是object的话,require在当前位置添加 + if (schema.type === 'object') { + if (!schema.required) { + schema.required = []; + } + schema.required = [...schema.required, name]; + } else { + // 在父级添加 + const parentPointer = pointer.split('/').slice(0, -1).join('/'); + const parentSchema = this.getSchemaByPoint(parentPointer); + + if (!parentSchema.required) { + parentSchema.required = []; + } + parentSchema.required = [...parentSchema.required, name]; + } + } + } + return false; + }; + + /** + * 动态表单更新属性 + * @param property + * @returns + */ + updateField = (options: { + pointer: string; // 指定属性路径,如 /a/b + key: 'variableName' | 'variableType' | 'description' | 'required'; + value: any; + currentVariableName: string; + }) => { + const { pointer, key, value, currentVariableName } = options; + if (typeof this.jsonschema !== 'boolean') { + const schema = this.getSchemaByPoint(pointer); + if (schema.type === 'object') { + if (schema.properties) { + if (key === 'variableName') { + const old = schema.properties?.[currentVariableName]; + if (value !== currentVariableName) { + schema.properties[value] = old; + delete schema.properties[currentVariableName]; + } else { + message.info('变量名不能和已有变量名相同'); + return false; + } + return true; + } + if (key === 'variableType') { + if ((schema.properties[currentVariableName] as JSONSchema7).type) { + // 处理数组类型 + if (value.startsWith('Array<')) { + const t = ( + value.replace('Array<', '').replace('>', '') as string + ).toLocaleLowerCase(); + schema.properties[currentVariableName].type = 'array'; + schema.properties[currentVariableName].items = { + type: t, + }; + if (t === 'object') { + schema.properties[currentVariableName].items.properties = {}; + } + return true; + } + if (value === 'object') { + schema.properties[currentVariableName].type = value; + schema.properties[currentVariableName].properties = {}; + return true; + } + + // 基础类型 + schema.properties[currentVariableName].type = value; + delete schema.properties[currentVariableName].items; + delete schema.properties[currentVariableName].properties; + + return true; + } + } + if (key === 'description') { + if (schema.properties[currentVariableName] as JSONSchema7) { + schema.properties[currentVariableName].description = value; + return true; + } + } + if (key === 'required') { + if (!this.isRandomName(currentVariableName)) { + if (schema.properties[currentVariableName]) { + if (!schema.required) { + schema.required = []; + } + if (value) { + if (!schema.required?.includes(value)) { + schema.required?.push(currentVariableName); + } + } else { + if (schema.required?.includes(currentVariableName)) { + schema.required = schema.required.filter( + (item) => item !== currentVariableName, + ); + } + } + + return true; + } + } + } + } + } + } + return false; + }; + + updateSchema(schema: JSONSchema7) { + Object.assign(this.jsonschema, schema); + } + + log() { + return JSON.stringify(this.jsonschema, null, 4); + } +} + +export const variableTypeOptions: { + label: string; + value: + | JSONSchema7TypeName + | 'Array' + | 'Array' + | 'Array' + | 'Array' + | 'Array'; +}[] = [ + { + label: 'String', + value: 'string', + }, + { + label: 'Integer', + value: 'integer', + }, + { + label: 'Boolean', + value: 'boolean', + }, + { + label: 'Number', + value: 'number', + }, + { + label: 'Object', + value: 'object', + }, + + { + label: 'Array', + value: 'Array', + }, + { + label: 'Array', + value: 'Array', + }, + { + label: 'Array', + value: 'Array', + }, + { + label: 'Array', + value: 'Array', + }, + { + label: 'Array', + value: 'Array', + }, +]; diff --git a/web/packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap b/web/packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap new file mode 100644 index 0000000..6729cd7 --- /dev/null +++ b/web/packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap @@ -0,0 +1,65 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`addField 添加表单field 1`] = ` +"{ + "$id": "5", + "type": "object", + "properties": { + "a": { + "type": "object", + "description": "this is a", + "order": 1, + "properties": {} + } + }, + "required": [] +}" +`; + +exports[`addField 添加表单field1 1`] = ` +"{ + "$id": "6", + "type": "object", + "properties": { + "a": { + "type": "object", + "description": "this is a", + "order": 1, + "properties": { + "b": { + "type": "string", + "description": "this is desc" + }, + "subA": { + "type": "object", + "description": "this is desc", + "order": 1, + "properties": { + "aryC": { + "type": "array", + "description": "this is desc", + "order": 1 + } + }, + "required": [ + "aryC" + ] + } + }, + "required": [ + "b", + "subA" + ] + }, + "first": { + "type": "object", + "description": "this is a", + "order": 2, + "properties": {} + } + }, + "required": [ + "first" + ] +}" +`; diff --git a/web/packages/magent-flow/src/spec/node.test.ts b/web/packages/magent-flow/src/spec/node.test.ts new file mode 100644 index 0000000..02375ee --- /dev/null +++ b/web/packages/magent-flow/src/spec/node.test.ts @@ -0,0 +1,199 @@ +import { FormSchema } from './FormSchema'; + +describe('getSchemaByPoint', () => { + it('基础路径 /', () => { + const input = new FormSchema(); + input.jsonschema = { + type: 'object', + properties: { + a: { + type: 'string', + description: 'this is a', + }, + b: { + type: 'object', + properties: { + c: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + }, + }, + }; + + expect(input.getSchemaByPoint('/')).toEqual({ + type: 'object', + properties: { + a: { + type: 'string', + description: 'this is a', + }, + b: { + type: 'object', + properties: { + c: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + }, + }, + }); + }); + + it('如果对应路径没有参数,应该创建一个properties对象,并且返回该对象', () => { + const input = new FormSchema(); + input.jsonschema = { + type: 'object', + properties: {}, + }; + + const got = input.getSchemaByPoint('/a'); + // 没有对应的属性 + expect(got).toEqual({}); + + expect(input.jsonschema).toEqual({ + type: 'object', + properties: { + a: {}, + }, + }); + }); + + it('获取对应的schema', () => { + const input = new FormSchema(); + input.jsonschema = { + type: 'object', + properties: { + a: { + type: 'string', + description: 'this is a', + }, + b: { + type: 'object', + properties: { + c: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + }, + }, + }; + expect(input.getSchemaByPoint('/a')).toEqual({ + type: 'string', + description: 'this is a', + }); + + expect(input.getSchemaByPoint('/b')).toEqual({ + type: 'object', + properties: { + c: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + }); + }); + + it('数组则返回对应的数组对象', () => { + const input = new FormSchema(); + input.jsonschema = { + type: 'object', + properties: { + a: { + type: 'string', + description: 'this is a', + }, + b: { + type: 'object', + properties: { + c: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + }, + }, + }; + + // 数组则返回对应的对象 + expect(input.getSchemaByPoint('/b/c')).toEqual({ + type: 'array', + items: { + type: 'string', + }, + }); + }); +}); + +describe('addField', () => { + it('添加表单field', () => { + const input = new FormSchema(); + input.addField({ + pointer: '/', // 指定属性路径,如 /a/b + name: 'a', + type: 'object', + description: 'this is a', + required: false, + }); + const got = input.log(); + console.log(got, '==got'); + expect(got).toMatchSnapshot(); + // expect(1).toBe(0); + }); + + it('添加表单field1', () => { + const input = new FormSchema(); + input.addField({ + pointer: '/', // 指定属性路径,如 /a/b + name: 'a', + type: 'object', + description: 'this is a', + required: false, + }); + console.log(input.log(), 'log1'); + input.addField({ + pointer: '/a/b', // 指定属性路径,如 /a/b + name: 'b', + type: 'string', + description: 'this is desc', + required: true, + }); + input.addField({ + pointer: '/a', // 指定属性路径,如 /a/b + name: 'subA', + type: 'object', + description: 'this is desc', + required: true, + }); + input.addField({ + pointer: '/a/subA', // 指定属性路径,如 /a/b + name: 'aryC', + type: 'array', + description: 'this is desc', + required: true, + }); + input.addField({ + pointer: '/', // 指定属性路径,如 /a/b + name: 'first', + type: 'object', + description: 'this is a', + required: true, + }); + const got = input.log(); + console.log(got); + expect(got).toMatchSnapshot(); + }); +}); diff --git a/web/packages/magent-flow/src/spec/node.ts b/web/packages/magent-flow/src/spec/node.ts new file mode 100644 index 0000000..3994e02 --- /dev/null +++ b/web/packages/magent-flow/src/spec/node.ts @@ -0,0 +1,82 @@ +import { + NodeDataConfigType, + NodeDataMetaType, + NodeDataType, + NodeTypeEnum, +} from '@/interfaces/flow'; +import { FormSchema } from './FormSchema'; +import { UUID } from './uuid'; + +// 不同类型的节点的基础类 +// + +/** + * 开始节点 + * 只设置输入 + * 输出和输入一致 + */ +export class StartNode implements NodeDataType { + id: string = UUID.getInstance().uniqueID(); + + type: NodeTypeEnum = NodeTypeEnum.Start; + + config: NodeDataConfigType | undefined = { + params: undefined, + inputs: new FormSchema(), + outputs: new FormSchema(), + }; + + nodeMeta: NodeDataMetaType = { + title: '开始节点', + description: '开始节点', + }; + + toJson() { + const node: NodeDataType = { + id: this.id, + nodeType: this.nodeType, + nodeMeta: this.nodeMeta, + config: this.config, + }; + return JSON.stringify(node); + } + + fromJson(json: string) { + try { + const node: NodeDataType = JSON.parse(json); + + this.id = node.id; + this.nodeType = node.nodeType; + this.nodeMeta = node.nodeMeta; + this.config = node.config; + } catch (error) {} + } + + toXYFlowJson() {} +} + +// /** +// * 插件节点 +// */ +// export class PluginNode implements FlowNode { +// extend(e) {} +// } +// class BingPluginNode extends PluginNode {} + +// new BingPluginNode().extend({ +// inpot: (JSONSchema = { +// type: 'object', +// properties: { +// count: { +// type: 'integer', +// }, +// offset: { +// type: 'integer', +// }, +// query: { +// type: 'string', +// }, +// }, +// required: ['a'], +// }), +// }); diff --git a/web/packages/magent-flow/src/spec/test-jsonschema.json b/web/packages/magent-flow/src/spec/test-jsonschema.json new file mode 100644 index 0000000..6a3b36f --- /dev/null +++ b/web/packages/magent-flow/src/spec/test-jsonschema.json @@ -0,0 +1,87 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "a": { + "type": "integer" + }, + "b": { + "type": "string" + }, + "c": { + "type": "boolean" + }, + "e": { + "type": "object", + "properties": { + "f": { + "type": "integer" + }, + "g": { + "type": "string" + }, + "h": { + "type": "boolean" + }, + "j": { + "type": "object", + "properties": { + "k": { + "type": "integer" + }, + "l": { + "type": "string" + }, + "m": { + "type": "boolean" + } + }, + "required": ["k", "l", "m", "n"] + } + }, + "required": ["f", "g", "h", "i", "j"] + }, + "f": { + "type": "array", + "items": [ + { + "type": "integer" + } + ] + }, + "g": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + }, + "h": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "i": { + "type": "integer" + }, + "j": { + "type": "string" + }, + "k": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + } + }, + "required": ["i", "j", "k"] + } + ] + } + }, + "required": ["a", "b", "c", "d", "e", "f", "g", "h"] +} diff --git a/web/packages/magent-flow/src/spec/uuid.ts b/web/packages/magent-flow/src/spec/uuid.ts new file mode 100644 index 0000000..107c8f1 --- /dev/null +++ b/web/packages/magent-flow/src/spec/uuid.ts @@ -0,0 +1,21 @@ +export class UUID { + private static instance: UUID; + + static getInstance() { + if (!UUID.instance) { + UUID.instance = new UUID(); + } + return UUID.instance; + } + + private _id = 0; + + /** + * 返回一个数字id + * @returns + */ + uniqueID() { + this._id += 1; + return this._id.toString(); + } +} diff --git a/web/packages/magent-flow/src/stores/useFlowStore.ts b/web/packages/magent-flow/src/stores/useFlowStore.ts new file mode 100644 index 0000000..f175086 --- /dev/null +++ b/web/packages/magent-flow/src/stores/useFlowStore.ts @@ -0,0 +1,324 @@ +import type { + Connection, + Edge, + EdgeChange, + Node, + NodeChange, + OnEdgesChange, + OnNodesChange, + ReactFlowInstance, + Viewport, + XYPosition, +} from '@xyflow/react'; +import { addEdge, applyEdgeChanges, applyNodeChanges } from '@xyflow/react'; +import { cloneDeep } from 'lodash'; +import { create } from 'zustand'; + +import type { NodeType } from '@/interfaces/flow'; +import { cleanEdges, getNodeId } from '@/utils/reactflowUtils'; + +interface AdjacencyList { + [key: number]: number[]; +} + +interface FlowStoreType { + nodes: Node[]; + edges: Edge[]; + onNodesChange: OnNodesChange; + onEdgesChange: OnEdgesChange; + + reactFlowInstance: ReactFlowInstance | null; + setReactFlowInstance: (newState: ReactFlowInstance) => void; + setNodes: ( + update: Node[] | ((oldState: Node[]) => Node[]), + skipSave?: boolean, + ) => void; + setEdges: ( + update: Edge[] | ((oldState: Edge[]) => Edge[]), + skipSave?: boolean, + ) => void; + setNode: (id: string, update: Node | ((oldState: Node) => Node)) => void; + getNode: (id: string) => Node | undefined; + deleteNode: (nodeId: string | Array) => void; + deleteEdge: (edgeId: string | Array) => void; + onConnect: (connection: Connection) => void; + getFlow: () => { nodes: Node[]; edges: Edge[]; viewport: Viewport }; + paste: any; + + findUpstreamNodes: (id: string) => Node[]; +} + +export const useFlowStore = create((set, get) => { + // DFS 查找上游节点 + const findUpstreamNodes = ( + nodes: Node[], + edges: Edge[], + targetNode: string, + ): Node[] => { + const adjList: AdjacencyList = {}; + nodes.forEach((node) => { + adjList[node.id] = []; + }); + edges.forEach((edge) => { + adjList[edge.source].push(edge.target); + }); + + const visited = new Set(); + const result = new Set(); + + const dfs = (node: string) => { + if (visited.has(node)) { + return; + } + visited.add(node); + + if (adjList[node]) { + adjList[node].forEach((upstreamNode) => { + result.add(upstreamNode); + dfs(upstreamNode); + }); + } + }; + + console.log('🚀 ~ useFlowStore ~ nodes:', nodes, edges, targetNode); + console.log('🚀 ~ adjList', adjList); + + dfs(targetNode); + console.log('🚀 ~ result', result); + return get().nodes.filter((node) => Array.from(result).includes(node.id)); + }; + + return { + nodes: [], + edges: [], + reactFlowInstance: null, + setReactFlowInstance: (newState) => { + set({ reactFlowInstance: newState }); + }, + getFlow: () => { + return { + nodes: get().nodes, + edges: get().edges, + viewport: get().reactFlowInstance?.getViewport() ?? { + x: 0, + y: 0, + zoom: 1, + }, + }; + }, + onNodesChange: (changes: NodeChange[]) => { + set({ + nodes: applyNodeChanges(changes, get().nodes), + }); + }, + onEdgesChange: (changes: EdgeChange[]) => { + set({ + edges: applyEdgeChanges(changes, get().edges), + }); + }, + setNode: (id: string, change: Node | ((oldState: Node) => Node)) => { + const newChange = + typeof change === 'function' + ? change(get().nodes.find((node) => node.id === id)!) + : change; + get().setNodes((oldNodes) => + oldNodes.map((node) => { + if (node.id === id) { + // if ((node.data as NodeDataType).node?.frozen) { + // (newChange.data as NodeDataType).node!.frozen = false; + // } + return newChange; + } + return node; + }), + ); + }, + setNodes: (change) => { + const newChange = typeof change === 'function' ? change(get().nodes) : change; + const newEdges = cleanEdges(newChange, get().edges); + // const { inputs, outputs } = getInputsAndOutputs(newChange); + + set({ + edges: newEdges, + nodes: newChange, + // flowState: undefined, + // inputs, + // outputs, + // hasIO: inputs.length > 0 || outputs.length > 0, + }); + + // const flowsManager = useFlowsManagerStore.getState(); + // if (!get().isBuilding && !skipSave && get().onFlowPage) { + // flowsManager.autoSaveCurrentFlow( + // newChange, + // newEdges, + // get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }, + // ); + // } + }, + + setEdges: (change) => { + const newChange = typeof change === 'function' ? change(get().edges) : change; + set({ + edges: newChange, + // flowState: undefined, + }); + + // const flowsManager = useFlowsManagerStore.getState(); + // if (!get().isBuilding && !skipSave && get().onFlowPage) { + // flowsManager.autoSaveCurrentFlow( + // get().nodes, + // newChange, + // get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }, + // ); + // } + }, + getNode: (id: string) => { + return get().nodes.find((node) => node.id === id); + }, + + onConnect: (connection) => { + let newEdges: Edge[] = []; + get().setEdges((oldEdges) => { + newEdges = addEdge( + { + ...connection, + data: { + targetHandle: connection.targetHandle!, + sourceHandle: connection.sourceHandle!, + }, + // style: { stroke: "#555" }, + type: 'custom', + // className: "stroke-foreground stroke-connection", + }, + oldEdges, + ); + + console.log('🚀 ~ get ~ newEdges:', newEdges); + return newEdges; + }); + }, + deleteNode: (nodeId) => { + get().setNodes( + get().nodes.filter((node) => + typeof nodeId === 'string' ? node.id !== nodeId : !nodeId.includes(node.id), + ), + ); + }, + deleteEdge: (edgeId) => { + get().setEdges( + get().edges.filter((edge) => + typeof edgeId === 'string' ? edge.id !== edgeId : !edgeId.includes(edge.id), + ), + ); + }, + paste: (selection: { nodes: Node[]; edge: Edge[] }, position: XYPosition) => { + //TODO:页面唯一节点检测 + // if ( + // selection.nodes.some((node) => node.data.type === 'ChatInput') && + // checkChatInput(get().nodes) + // ) { + // useAlertStore.getState().setErrorData({ + // title: 'Error pasting components', + // list: ['You can only have one ChatInput component in the flow'], + // }); + // return; + // } + + let minimumX = Infinity; + let minimumY = Infinity; + // let idsMap = {}; + let newNodes: Node[] = get().nodes; + // let newEdges = get().edges; + selection.nodes.forEach((node: Node) => { + if (node.position.y < minimumY) { + minimumY = node.position.y; + } + if (node.position.x < minimumX) { + minimumX = node.position.x; + } + }); + + const insidePosition = position.paneX + ? { x: position.paneX + position.x, y: position.paneY! + position.y } + : get().reactFlowInstance!.screenToFlowPosition({ + x: position.x, + y: position.y, + }); + + selection.nodes.forEach((node: Node) => { + // Generate a unique node ID + const newId = getNodeId(node.data.type as string); + + // idsMap[node.id] = newId; + + // Create a new node object + const newNode: NodeType = { + id: newId, + type: node.data.type, + position: { + x: insidePosition.x + node.position!.x - minimumX, + y: insidePosition.y + node.position!.y - minimumY, + }, + data: { + ...cloneDeep(node.data), + id: newId, + } as any, + }; + // updateGroupRecursion( + // newNode, + // selection.edges, + // useGlobalVariablesStore.getState().unavaliableFields, + // useGlobalVariablesStore.getState().globalVariablesEntries, + // ); + + // Add the new node to the list of nodes in state + newNodes = newNodes + .map((node) => ({ ...node, selected: false })) + .concat({ ...newNode, selected: false }); + }); + get().setNodes(newNodes); + + // selection.edges.forEach((edge: Edge) => { + // let source = idsMap[edge.source]; + // let target = idsMap[edge.target]; + // const sourceHandleObject: sourceHandleType = scapeJSONParse( + // edge.sourceHandle!, + // ); + // let sourceHandle = scapedJSONStringfy({ + // ...sourceHandleObject, + // id: source, + // }); + // sourceHandleObject.id = source; + + // edge.data.sourceHandle = sourceHandleObject; + // const targetHandleObject: targetHandleType = scapeJSONParse( + // edge.targetHandle!, + // ); + // let targetHandle = scapedJSONStringfy({ + // ...targetHandleObject, + // id: target, + // }); + // targetHandleObject.id = target; + // edge.data.targetHandle = targetHandleObject; + // let id = getHandleId(source, sourceHandle, target, targetHandle); + // newEdges = addEdge( + // { + // source, + // target, + // sourceHandle, + // targetHandle, + // id, + // data: cloneDeep(edge.data), + // selected: false, + // }, + // newEdges.map((edge) => ({ ...edge, selected: false })), + // ); + // }); + // get().setEdges(newEdges); + }, + findUpstreamNodes: (id: string) => { + return findUpstreamNodes(get().nodes, get().edges, id); + }, + }; +}); diff --git a/web/packages/magent-flow/src/stores/useKnowledgeStore.ts b/web/packages/magent-flow/src/stores/useKnowledgeStore.ts new file mode 100644 index 0000000..908657a --- /dev/null +++ b/web/packages/magent-flow/src/stores/useKnowledgeStore.ts @@ -0,0 +1,19 @@ +import { create } from 'zustand'; + +export interface Knowledge { + name: string; + id: string; + description?: string; +} + +export interface KnowledgeStoreType { + knowledges: Knowledge[]; + setKnowledges: (knowledges: Knowledge[]) => void; +} + +export const useKnowledgeStore = create((set, get) => ({ + knowledges: [], + setKnowledges: (knowledges: Knowledge[]) => { + set({ knowledges }); + }, +})); diff --git a/web/packages/magent-flow/src/stores/useModelStore.ts b/web/packages/magent-flow/src/stores/useModelStore.ts new file mode 100644 index 0000000..fa9a09e --- /dev/null +++ b/web/packages/magent-flow/src/stores/useModelStore.ts @@ -0,0 +1,33 @@ +import { create } from 'zustand'; + +export interface Model { + id: string; + name: string; + group?: string; + description?: string; +} + +export interface ModelConfig { + temperature?: number; + top_p?: number; + max_tokens?: number; + [key: string]: number | undefined; +} + +export interface ModelStoreType { + models: Model[]; + setModels: (models: Model[]) => void; + modelConfig: ModelConfig; + setModelConfig: (config: ModelConfig) => void; +} + +export const useModelStore = create((set, get) => ({ + models: [], + setModels: (models: Model[]) => { + set({ models }); + }, + modelConfig: {}, + setModelConfig: (modelConfig: ModelConfig) => { + set({ modelConfig }); + }, +})); diff --git a/web/packages/magent-flow/src/stores/useShortcutsStore.ts b/web/packages/magent-flow/src/stores/useShortcutsStore.ts new file mode 100644 index 0000000..78e3a3f --- /dev/null +++ b/web/packages/magent-flow/src/stores/useShortcutsStore.ts @@ -0,0 +1,86 @@ +import { create } from 'zustand'; + +import { defaultShortcuts } from '@/constants/constant'; + +export type shortcutsStoreType = { + updateUniqueShortcut: (name: string, combination: string) => void; + output: string; + play: string; + flow: string; + group: string; + cut: string; + paste: string; + api: string; + open: string; + undo: string; + redo: string; + advanced: string; + minimize: string; + code: string; + copy: string; + duplicate: string; + component: string; + docs: string; + save: string; + delete: string; + update: string; + download: string; + freeze: string; + FreezePath: string; + shortcuts: Array<{ + name: string; + shortcut: string; + }>; + setShortcuts: (newShortcuts: Array<{ name: string; shortcut: string }>) => void; + getShortcutsFromStorage: () => void; +}; + +export const useShortcutsStore = create((set, get) => ({ + shortcuts: defaultShortcuts, + setShortcuts: (newShortcuts) => { + set({ shortcuts: newShortcuts }); + }, + output: 'o', + play: 'p', + flow: 'mod+b', + undo: 'mod+z', + redo: 'mod+y', + open: 'mod+k', + advanced: 'mod+shift+a', + minimize: 'mod+shift+q', + code: 'space', + copy: 'mod+c', + duplicate: 'mod+d', + component: 'mod+shift+s', + docs: 'mod+shift+d', + save: 'mod+s', + delete: 'backspace', + group: 'mod+g', + cut: 'mod+x', + paste: 'mod+v', + api: 'r', + update: 'mod+u', + download: 'mod+j', + freeze: 'mod+f', + FreezePath: 'mod+shift+f', + updateUniqueShortcut: (name, combination) => { + set({ + [name]: combination, + }); + }, + getShortcutsFromStorage: () => { + if (localStorage.getItem('langflow-shortcuts')) { + const savedShortcuts = localStorage.getItem('langflow-shortcuts'); + const savedArr = JSON.parse(savedShortcuts!); + savedArr.forEach(({ name, shortcut }) => { + const shortcutName = name.split(' ')[0].toLowerCase(); + set({ + [shortcutName]: shortcut, + }); + }); + get().setShortcuts(JSON.parse(savedShortcuts!)); + } + }, +})); + +useShortcutsStore.getState().getShortcutsFromStorage(); diff --git a/web/packages/magent-flow/src/stores/useUndoRedoStore.ts b/web/packages/magent-flow/src/stores/useUndoRedoStore.ts new file mode 100644 index 0000000..401c90b --- /dev/null +++ b/web/packages/magent-flow/src/stores/useUndoRedoStore.ts @@ -0,0 +1,101 @@ +import type { Edge, Node } from '@xyflow/react'; +import { cloneDeep } from 'lodash'; +import { create } from 'zustand'; + +import { useFlowStore } from './useFlowStore'; + +interface FlowRedoUndoStoreType { + undo: () => void; + redo: () => void; + takeSnapshot: () => void; +} + +export type UseUndoRedoOptions = { + maxHistorySize: number; + enableShortcuts: boolean; +}; + +interface Snap { + nodes: Node[]; + edges: Edge[]; +} + +const defaultOptions: UseUndoRedoOptions = { + maxHistorySize: 100, + enableShortcuts: true, +}; + +let past: Snap[] = []; + +let future: Snap[] = []; + +export const useUndoRedoStore = create(() => ({ + takeSnapshot: () => { + // const currentFlowId = get().currentFlowId; + // push the current graph to the past state + const flowStore = useFlowStore.getState(); + const newState = { + nodes: cloneDeep(flowStore.nodes), + edges: cloneDeep(flowStore.edges), + }; + const pastLength = past?.length ?? 0; + if ( + pastLength > 0 && + JSON.stringify(past[pastLength - 1]) === JSON.stringify(newState) + ) { + return; + } + if (pastLength > 0) { + past = past.slice(pastLength - defaultOptions.maxHistorySize + 1, pastLength); + + past.push(newState); + } else { + past = [newState]; + } + + future = []; + }, + undo: () => { + console.log('🚀 ~ useUndoRedoStore ~ undo:'); + const newState = useFlowStore.getState(); + + const pastLength = past?.length ?? 0; + const pastState = past?.[pastLength - 1] ?? null; + + if (pastState) { + past = past.slice(0, pastLength - 1); + + if (!future) { + future = []; + } + future.push({ + nodes: newState.nodes, + edges: newState.edges, + }); + + newState.setNodes(pastState.nodes); + newState.setEdges(pastState.edges); + } + }, + redo: () => { + const newState = useFlowStore.getState(); + + const futureLength = future?.length ?? 0; + const futureState = future?.[futureLength - 1] ?? null; + + if (futureState) { + future = future.slice(0, futureLength - 1); + + if (!past) { + past = []; + } + past.push({ + nodes: newState.nodes, + edges: newState.edges, + }); + + newState.setNodes(futureState.nodes); + newState.setEdges(futureState.edges); + } + }, +})); diff --git a/web/packages/magent-flow/src/tailwind.css b/web/packages/magent-flow/src/tailwind.css new file mode 100644 index 0000000..41677bf --- /dev/null +++ b/web/packages/magent-flow/src/tailwind.css @@ -0,0 +1,4 @@ +/* stylelint-disable at-rule-no-unknown */ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/web/packages/magent-flow/src/utils/basic.ts b/web/packages/magent-flow/src/utils/basic.ts new file mode 100644 index 0000000..a1db376 --- /dev/null +++ b/web/packages/magent-flow/src/utils/basic.ts @@ -0,0 +1,8 @@ +export function classNames(...classes: Array): string { + return classes.filter(Boolean).join(' '); +} + +export function capitalizeFirstLetter(s: string) { + if (!s) return ''; + return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); +} diff --git a/web/packages/magent-flow/src/utils/index.tsx b/web/packages/magent-flow/src/utils/index.tsx new file mode 100644 index 0000000..e1ad5ae --- /dev/null +++ b/web/packages/magent-flow/src/utils/index.tsx @@ -0,0 +1,2 @@ +export * from './basic'; +export * from './reactflowUtils'; diff --git a/web/packages/magent-flow/src/utils/reactflowUtils.ts b/web/packages/magent-flow/src/utils/reactflowUtils.ts new file mode 100644 index 0000000..07816ba --- /dev/null +++ b/web/packages/magent-flow/src/utils/reactflowUtils.ts @@ -0,0 +1,13 @@ +import { Edge } from '@xyflow/react'; +import { cloneDeep } from 'lodash'; +import { v4 } from 'uuid'; + +export function cleanEdges(nodes: any[], edges: Edge[]) { + let newEdges = cloneDeep(edges); + + return newEdges; +} + +export function getNodeId(nodeType: string) { + return nodeType + '-' + v4(); +} diff --git a/web/packages/magent-flow/src/utils/wrappedClass.ts b/web/packages/magent-flow/src/utils/wrappedClass.ts new file mode 100644 index 0000000..eff34d3 --- /dev/null +++ b/web/packages/magent-flow/src/utils/wrappedClass.ts @@ -0,0 +1,4 @@ +const isWrappedWithClass = (event: any, className: string | undefined) => + event.target.closest(`.${className}`); + +export default isWrappedWithClass; diff --git a/web/packages/magent-flow/tailwind.config.js b/web/packages/magent-flow/tailwind.config.js new file mode 100644 index 0000000..9cfd53f --- /dev/null +++ b/web/packages/magent-flow/tailwind.config.js @@ -0,0 +1,7 @@ +module.exports = { + content: [ + './src/pages/**/*.tsx', + './src/components/**/*.tsx', + './src/layouts/**/*.tsx', + ], +}; diff --git a/web/packages/magent-flow/tsconfig.json b/web/packages/magent-flow/tsconfig.json new file mode 100644 index 0000000..e7a514f --- /dev/null +++ b/web/packages/magent-flow/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "es", + "declarationDir": "es", + "paths": { + "@/*": ["./src/*"] + } + }, + "types": ["jest"], + "exclude": ["node_modules"], + "include": ["src"] +} From 2ae15d3f02ef10cc46937145817a59253f6d8475 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 27 Aug 2024 15:19:52 +0800 Subject: [PATCH 02/78] chore(flow): migrate to nodenext code style --- web/packages/magent-flow/package.json | 12 ++++++--- .../magent-flow/src/FormSchema/index.ts | 2 +- .../magent-flow/src/RefForm/index.tsx | 2 +- .../src/SchemaConfigForm/index.tsx | 4 +-- .../AIBasic/CascaderInNode/index.tsx | 6 +++-- .../OutputVariable/index.tsx | 3 +-- .../components/AIBasic/PromptEditor/hooks.ts | 4 +-- .../components/AIBasic/PromptEditor/index.tsx | 25 +++++++++++-------- .../plugins/component-picker-block/hooks.tsx | 10 ++++---- .../plugins/component-picker-block/index.tsx | 14 +++++------ .../component-picker-block/prompt-option.tsx | 2 +- .../variable-option.tsx | 2 +- .../PromptEditor/plugins/custom-text/node.tsx | 12 ++++----- .../plugins/on-blur-or-focus-block.tsx | 8 ++++-- .../PromptEditor/plugins/update-block.tsx | 6 ++--- .../plugins/variable-block/index.tsx | 2 +- .../plugins/variable-value-block/index.tsx | 6 ++--- .../plugins/variable-value-block/node.tsx | 12 ++++----- .../components/AIBasic/PromptEditor/utils.ts | 4 +-- .../components/AIBasic/SelectInNode/index.tsx | 7 +++--- .../src/components/CustomEdge/index.tsx | 4 +-- .../magent-flow/src/components/Flow/index.tsx | 16 ++++++------ .../magent-flow/src/components/Flow/keys.ts | 4 ++- .../src/components/FlowController/index.tsx | 1 - .../src/components/FlowWithPanel/index.tsx | 25 +++++++++++-------- .../src/components/Node/AgentNode/index.tsx | 14 +++++------ .../src/components/Node/CommonNode/index.tsx | 6 +++-- .../src/components/Node/EndNode/index.tsx | 11 ++++---- .../src/components/Node/IfElseNode/index.tsx | 13 +++++----- .../components/Node/KnowledgeNode/index.tsx | 17 +++++++------ .../src/components/Node/LLMNode/index.tsx | 22 ++++++++-------- .../Node/NodeWrapper/Status/index.tsx | 3 ++- .../src/components/Node/NodeWrapper/index.tsx | 4 +-- .../src/components/Node/StartNode/index.tsx | 9 ++++--- .../src/components/NodePanel/index.tsx | 3 ++- .../src/components/ReferenceForm/index.tsx | 6 ++--- .../src/components/ReferenceSelect/index.tsx | 5 ++-- .../src/components/VariableForm/index.tsx | 4 +-- web/packages/magent-flow/src/index.ts | 12 ++++----- web/packages/magent-flow/src/spec/node.ts | 11 ++++---- .../magent-flow/src/stores/useFlowStore.ts | 4 +-- .../src/stores/useShortcutsStore.ts | 2 +- .../src/stores/useUndoRedoStore.ts | 2 +- web/packages/magent-flow/src/utils/basic.ts | 4 ++- web/packages/magent-flow/src/utils/index.tsx | 4 +-- .../magent-flow/src/utils/reactflowUtils.ts | 4 +-- 46 files changed, 193 insertions(+), 160 deletions(-) diff --git a/web/packages/magent-flow/package.json b/web/packages/magent-flow/package.json index 397fd69..770776b 100644 --- a/web/packages/magent-flow/package.json +++ b/web/packages/magent-flow/package.json @@ -50,23 +50,29 @@ "@ant-design/icons": "^5.1.0", "@babel/runtime": "^7.18.0", "@floating-ui/react": "^0.26.22", + "@lexical/code": "^0.17.0", "@lexical/react": "^0.17.0", + "@lexical/utils": "^0.17.0", "@types/json-schema": "^7.0.15", "@xyflow/react": "^12.0.2", - "antd": "^5.19.2", + "ahooks": "^3.8.1", "ajv": "^8.17.1", + "antd": "^5.19.2", + "classnames": "^2.3.2", "js-yaml": "^4.1.0", "lexical": "^0.17.0", "lodash": "^4.17.21", + "react": "^18.0.0", + "react-dom": "^18.0.0", "react-hotkeys-hook": "^4.5.0", "short-unique-id": "^5.2.0", "styled-components": "^6.0.7", - "react": "^18.0.0", - "react-dom": "^18.0.0", "uuid": "^10.0.0", "zustand": "^4.5.4" }, "devDependencies": { + "@types/classnames": "^2.3.1", + "@types/lodash": "^4.17.7", "@types/react": "^18.2.25", "@types/uuid": "^10.0.0", "tailwindcss": "^3" diff --git a/web/packages/magent-flow/src/FormSchema/index.ts b/web/packages/magent-flow/src/FormSchema/index.ts index e1ac908..51adf0b 100644 --- a/web/packages/magent-flow/src/FormSchema/index.ts +++ b/web/packages/magent-flow/src/FormSchema/index.ts @@ -5,7 +5,7 @@ import type { JSONSchema7TypeName, } from 'json-schema'; -import { UUID } from '@/spec/uuid'; +import { UUID } from '@/spec/uuid.js'; export type OrderJSONSchema7 = JSONSchema7 & { order: number; diff --git a/web/packages/magent-flow/src/RefForm/index.tsx b/web/packages/magent-flow/src/RefForm/index.tsx index 2df74aa..0dbe097 100644 --- a/web/packages/magent-flow/src/RefForm/index.tsx +++ b/web/packages/magent-flow/src/RefForm/index.tsx @@ -2,7 +2,7 @@ import { CaretRightOutlined } from '@ant-design/icons'; import { Button, Cascader, Collapse, Flex, Input, Select, Space, theme } from 'antd'; import React, { useEffect, useMemo, useState } from 'react'; -import type { NodeDataType } from '@/interfaces/flow'; +import type { NodeDataType } from '@/interfaces/flow.js'; interface CascaderOptions { value: string; diff --git a/web/packages/magent-flow/src/SchemaConfigForm/index.tsx b/web/packages/magent-flow/src/SchemaConfigForm/index.tsx index 6435a36..ad65dbf 100644 --- a/web/packages/magent-flow/src/SchemaConfigForm/index.tsx +++ b/web/packages/magent-flow/src/SchemaConfigForm/index.tsx @@ -11,8 +11,8 @@ import { Card, Checkbox, Collapse, Form, Input, Select, Space, theme } from 'ant import type { JSONSchema7 } from 'json-schema'; import React, { useState } from 'react'; -import { variableTypeOptions } from '@/FormSchema'; -import type { FormSchema, OrderJSONSchema7 } from '@/FormSchema'; +import { variableTypeOptions } from '@/FormSchema/index.js'; +import type { FormSchema, OrderJSONSchema7 } from '@/FormSchema/index.js'; // import { // FormSchema, diff --git a/web/packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx b/web/packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx index 05e606a..ae4b320 100644 --- a/web/packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx @@ -1,7 +1,9 @@ -import { classNames } from '@/utils'; -import { Cascader, CascaderProps } from 'antd'; +import type { CascaderProps } from 'antd'; +import { Cascader } from 'antd'; import React from 'react'; +import { classNames } from '@/utils/index.js'; + export const CascaderInNode = (props: CascaderProps) => { return ( { const { name, type } = props; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts index bdb0239..7644346 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts @@ -4,8 +4,8 @@ import { mergeRegister } from '@lexical/utils'; import type { Klass, LexicalEditor, TextNode } from 'lexical'; import { useCallback, useEffect } from 'react'; -import type { CustomTextNode } from './plugins/custom-text/node'; -import { registerLexicalTextEntity } from './utils'; +import type { CustomTextNode } from './plugins/custom-text/node.js'; +import { registerLexicalTextEntity } from './utils.js'; export function useLexicalTextEntity( getMatch: (text: string) => null | EntityMatch, diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx index 06d12a8..8e97314 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx @@ -7,16 +7,17 @@ import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'; import type { EditorState } from 'lexical'; import { $getRoot, TextNode } from 'lexical'; import React, { type FC } from 'react'; -import ComponentPickerBlock from './plugins/component-picker-block'; -import { CustomTextNode } from './plugins/custom-text/node'; -import OnBlurBlock from './plugins/on-blur-or-focus-block'; -import Placeholder from './plugins/placeholder'; -import UpdateBlock from './plugins/update-block'; -import VariableBlock from './plugins/variable-block'; -import VariableValueBlock from './plugins/variable-value-block'; -import { VariableValueBlockNode } from './plugins/variable-value-block/node'; -import type { ExternalToolBlockType, VariableBlockType } from './types'; -import { textToEditorState } from './utils'; + +import ComponentPickerBlock from './plugins/component-picker-block/index.js'; +import { CustomTextNode } from './plugins/custom-text/node.js'; +import OnBlurBlock from './plugins/on-blur-or-focus-block.js'; +import Placeholder from './plugins/placeholder.js'; +import UpdateBlock from './plugins/update-block.js'; +import VariableBlock from './plugins/variable-block/index.js'; +import VariableValueBlock from './plugins/variable-value-block/index.js'; +import { VariableValueBlockNode } from './plugins/variable-value-block/node.js'; +import type { ExternalToolBlockType, VariableBlockType } from './types.js'; +import { textToEditorState } from './utils.js'; export type PromptEditorProps = { instanceId?: string; @@ -74,7 +75,9 @@ const PromptEditor: FC = ({ .join('\n'); }); - if (onChange) onChange(text); + if (onChange) { + onChange(text); + } }; return ( diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx index a48a7a0..7cc91c8 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx @@ -3,12 +3,12 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext import { $insertNodes } from 'lexical'; import React, { useMemo } from 'react'; -import type { ExternalToolBlockType, VariableBlockType } from '../../types'; -import { $createCustomTextNode } from '../custom-text/node'; -import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../variable-block'; +import type { ExternalToolBlockType, VariableBlockType } from '../../types.js'; +import { $createCustomTextNode } from '../custom-text/node.js'; +import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../variable-block/index.js'; -import { PickerBlockMenuOption } from './menu'; -import { VariableMenuItem } from './variable-option'; +import { PickerBlockMenuOption } from './menu.js'; +import { VariableMenuItem } from './variable-option.js'; export const useVariableOptions = ( variableBlock?: VariableBlockType, diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx index ddb64af..6d67748 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx @@ -6,15 +6,15 @@ import type { TextNode } from 'lexical'; import React, { Fragment, memo, useCallback, useState } from 'react'; import ReactDOM from 'react-dom'; -import { useEventEmitterContextContext } from '@/context/event-emitter'; +import { useEventEmitterContextContext } from '@/context/event-emitter.js'; -import { useBasicTypeaheadTriggerMatch } from '../../hooks'; -import type { ExternalToolBlockType, VariableBlockType } from '../../types'; -import { $splitNodeContainingQuery } from '../../utils'; -import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../variable-block'; +import { useBasicTypeaheadTriggerMatch } from '../../hooks.js'; +import type { ExternalToolBlockType, VariableBlockType } from '../../types.js'; +import { $splitNodeContainingQuery } from '../../utils.js'; +import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../variable-block/index.js'; -import { useOptions } from './hooks'; -import type { PickerBlockMenuOption } from './menu'; +import { useOptions } from './hooks.js'; +import type { PickerBlockMenuOption } from './menu.js'; type ComponentPickerProps = { triggerString: string; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx index 43ff4dc..632b688 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import { memo } from 'react'; type PromptMenuItemMenuItemProps = { icon: JSX.Element; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx index 2dce466..e59f3f3 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import { memo } from 'react'; type VariableMenuItemProps = { title: string; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx index b660ce8..bda0c4b 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx @@ -2,11 +2,11 @@ import type { EditorConfig, NodeKey, SerializedTextNode } from 'lexical'; import { $createTextNode, TextNode } from 'lexical'; export class CustomTextNode extends TextNode { - static getType() { + static override getType() { return 'custom-text'; } - static clone(node: CustomTextNode) { + static override clone(node: CustomTextNode) { return new CustomTextNode(node.__text, node.__key); } @@ -14,13 +14,13 @@ export class CustomTextNode extends TextNode { super(text, key); } - createDOM(config: EditorConfig) { + override createDOM(config: EditorConfig) { const dom = super.createDOM(config); dom.classList.add('align-middle'); return dom; } - static importJSON(serializedNode: SerializedTextNode): TextNode { + static override importJSON(serializedNode: SerializedTextNode): TextNode { const node = $createTextNode(serializedNode.text); node.setFormat(serializedNode.format); node.setDetail(serializedNode.detail); @@ -29,7 +29,7 @@ export class CustomTextNode extends TextNode { return node; } - exportJSON(): SerializedTextNode { + override exportJSON(): SerializedTextNode { return { detail: this.getDetail(), format: this.getFormat(), @@ -41,7 +41,7 @@ export class CustomTextNode extends TextNode { }; } - isSimpleText() { + override isSimpleText() { return ( (this.__type === 'text' || this.__type === 'custom-text') && this.__mode === 0 ); diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx index d7de68c..8aa4791 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx @@ -30,7 +30,9 @@ const OnBlurBlock: FC = ({ onBlur, onFocus }) => { ); }, 200); - if (onBlur) onBlur(); + if (onBlur) { + onBlur(); + } return true; }, @@ -39,7 +41,9 @@ const OnBlurBlock: FC = ({ onBlur, onFocus }) => { editor.registerCommand( FOCUS_COMMAND, () => { - if (onFocus) onFocus(); + if (onFocus) { + onFocus(); + } return true; }, COMMAND_PRIORITY_EDITOR, diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx index c7ca926..e1d5a5c 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx @@ -1,11 +1,11 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { $insertNodes } from 'lexical'; -import { useEventEmitterContextContext } from '@/context/event-emitter'; +import { useEventEmitterContextContext } from '@/context/event-emitter.js'; -import { textToEditorState } from '../utils'; +import { textToEditorState } from '../utils.js'; -import { CustomTextNode } from './custom-text/node'; +import { CustomTextNode } from './custom-text/node.js'; export const PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER = 'PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER'; diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx index b1dc0bd..2b3c0b9 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx @@ -3,7 +3,7 @@ import { mergeRegister } from '@lexical/utils'; import { $insertNodes, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical'; import { useEffect } from 'react'; -import { CustomTextNode } from '../custom-text/node'; +import { CustomTextNode } from '../custom-text/node.js'; export const INSERT_VARIABLE_BLOCK_COMMAND = createCommand( 'INSERT_VARIABLE_BLOCK_COMMAND', diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx index 51a4784..3baae5c 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx @@ -2,10 +2,10 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext import type { TextNode } from 'lexical'; import { useCallback, useEffect } from 'react'; -import { useLexicalTextEntity } from '../../hooks'; +import { useLexicalTextEntity } from '../../hooks.js'; -import { $createVariableValueBlockNode, VariableValueBlockNode } from './node'; -import { getHashtagRegexString } from './utils'; +import { $createVariableValueBlockNode, VariableValueBlockNode } from './node.js'; +import { getHashtagRegexString } from './utils.js'; const REGEX = new RegExp(getHashtagRegexString(), 'i'); diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx index a53ebca..58ea90f 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx @@ -2,11 +2,11 @@ import type { EditorConfig, LexicalNode, NodeKey, SerializedTextNode } from 'lex import { $applyNodeReplacement, TextNode } from 'lexical'; export class VariableValueBlockNode extends TextNode { - static getType(): string { + static override getType(): string { return 'variable-value-block'; } - static clone(node: VariableValueBlockNode): VariableValueBlockNode { + static override clone(node: VariableValueBlockNode): VariableValueBlockNode { return new VariableValueBlockNode(node.__text, node.__key); } @@ -14,7 +14,7 @@ export class VariableValueBlockNode extends TextNode { super(text, key); } - createDOM(config: EditorConfig): HTMLElement { + override createDOM(config: EditorConfig): HTMLElement { const element = super.createDOM(config); element.classList.add( 'inline-flex', @@ -28,7 +28,7 @@ export class VariableValueBlockNode extends TextNode { return element; } - static importJSON(serializedNode: SerializedTextNode): TextNode { + static override importJSON(serializedNode: SerializedTextNode): TextNode { const node = $createVariableValueBlockNode(serializedNode.text); node.setFormat(serializedNode.format); node.setDetail(serializedNode.detail); @@ -37,7 +37,7 @@ export class VariableValueBlockNode extends TextNode { return node; } - exportJSON(): SerializedTextNode { + override exportJSON(): SerializedTextNode { return { detail: this.getDetail(), format: this.getFormat(), @@ -49,7 +49,7 @@ export class VariableValueBlockNode extends TextNode { }; } - canInsertTextBefore(): boolean { + override canInsertTextBefore(): boolean { return false; } } diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts index eb8a4bc..ca1f1cb 100644 --- a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts +++ b/web/packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts @@ -7,8 +7,8 @@ import { $isTextNode, } from 'lexical'; -import { CustomTextNode } from './plugins/custom-text/node'; -import type { MenuTextMatch } from './types'; +import { CustomTextNode } from './plugins/custom-text/node.js'; +import type { MenuTextMatch } from './types.js'; export function registerLexicalTextEntity( editor: LexicalEditor, diff --git a/web/packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx b/web/packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx index 2890d07..26bebc4 100644 --- a/web/packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx +++ b/web/packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx @@ -1,6 +1,7 @@ -import { classNames } from '@/utils'; -import { Select, SelectProps } from 'antd'; -import React from 'react'; +import type { SelectProps } from 'antd'; +import { Select } from 'antd'; + +import { classNames } from '@/utils/index.js'; export const SelectInNode = (props: SelectProps) => { return ( diff --git a/web/packages/magent-flow/src/components/CustomEdge/index.tsx b/web/packages/magent-flow/src/components/CustomEdge/index.tsx index a1baf20..a376b6c 100644 --- a/web/packages/magent-flow/src/components/CustomEdge/index.tsx +++ b/web/packages/magent-flow/src/components/CustomEdge/index.tsx @@ -1,5 +1,5 @@ -import { BaseEdge, EdgeProps, getBezierPath, MarkerType } from '@xyflow/react'; -import React from 'react'; +import type { EdgeProps } from '@xyflow/react'; +import { BaseEdge, getBezierPath, MarkerType } from '@xyflow/react'; export default function CustomEdge({ // id, diff --git a/web/packages/magent-flow/src/components/Flow/index.tsx b/web/packages/magent-flow/src/components/Flow/index.tsx index 7768021..e63b693 100644 --- a/web/packages/magent-flow/src/components/Flow/index.tsx +++ b/web/packages/magent-flow/src/components/Flow/index.tsx @@ -3,15 +3,14 @@ import { Background, ReactFlow } from '@xyflow/react'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; -import type { NodeType } from '@/interfaces/flow'; -import { useFlowStore } from '@/stores/useFlowStore'; -import { useShortcutsStore } from '@/stores/useShortcutsStore'; -import { useUndoRedoStore } from '@/stores/useUndoRedoStore'; -import { getNodeId } from '@/utils/reactflowUtils'; +import type { NodeType } from '@/interfaces/flow.js'; +import { useFlowStore } from '@/stores/useFlowStore.js'; +import { useShortcutsStore } from '@/stores/useShortcutsStore.js'; +import { useUndoRedoStore } from '@/stores/useUndoRedoStore.js'; +import { getNodeId } from '@/utils/reactflowUtils.js'; import CustomEdge from '../CustomEdge/index.js'; import { FlowController } from '../FlowController/index.js'; -import '@xyflow/react/dist/style.css'; import { handleCopy, @@ -21,7 +20,8 @@ import { handlePaste, handleRedo, handleUndo, -} from './keys'; +} from './keys.js'; +import '@xyflow/react/dist/style.css'; const edgeTypes = { custom: CustomEdge, @@ -138,7 +138,7 @@ function Flow(props: FlowProps) { return (
diff --git a/web/packages/magent-flow/src/components/Flow/keys.ts b/web/packages/magent-flow/src/components/Flow/keys.ts index b7a0f2b..abf603c 100644 --- a/web/packages/magent-flow/src/components/Flow/keys.ts +++ b/web/packages/magent-flow/src/components/Flow/keys.ts @@ -1,5 +1,7 @@ -import isWrappedWithClass from '@/utils/wrappedClass'; import { cloneDeep } from 'lodash'; + +import isWrappedWithClass from '@/utils/wrappedClass.js'; + export function handleUndo(e: KeyboardEvent, undo: any) { if (!isWrappedWithClass(e, 'noflow')) { e.preventDefault(); diff --git a/web/packages/magent-flow/src/components/FlowController/index.tsx b/web/packages/magent-flow/src/components/FlowController/index.tsx index e5ad6f7..3224b8b 100644 --- a/web/packages/magent-flow/src/components/FlowController/index.tsx +++ b/web/packages/magent-flow/src/components/FlowController/index.tsx @@ -1,5 +1,4 @@ import { Controls, MiniMap } from '@xyflow/react'; -import React from 'react'; export const FlowController = () => { return ( diff --git a/web/packages/magent-flow/src/components/FlowWithPanel/index.tsx b/web/packages/magent-flow/src/components/FlowWithPanel/index.tsx index f2b7e3b..8ed246c 100644 --- a/web/packages/magent-flow/src/components/FlowWithPanel/index.tsx +++ b/web/packages/magent-flow/src/components/FlowWithPanel/index.tsx @@ -1,15 +1,18 @@ -import { EventEmitterContextProvider } from '@/context/event-emitter'; -import { NodeDataType, NodeTypeEnum } from '@/interfaces/flow'; import yaml from 'js-yaml'; import React from 'react'; -import Flow from '../Flow'; -import { AgentNode } from '../Node/AgentNode'; -import { EndNode } from '../Node/EndNode'; -import { IfElseNode } from '../Node/IfElseNode'; -import { KnowledgeNode } from '../Node/KnowledgeNode'; -import { LLMNode } from '../Node/LLMNode'; -import { StartNode } from '../Node/StartNode'; -import { NodesPanel } from '../NodePanel'; + +import { EventEmitterContextProvider } from '@/context/event-emitter.js'; +import type { NodeDataType } from '@/interfaces/flow.js'; +import { NodeTypeEnum } from '@/interfaces/flow.js'; + +import Flow from '../Flow/index.js'; +import { AgentNode } from '../Node/AgentNode/index.js'; +import { EndNode } from '../Node/EndNode/index.js'; +import { IfElseNode } from '../Node/IfElseNode/index.js'; +import { KnowledgeNode } from '../Node/KnowledgeNode/index.js'; +import { LLMNode } from '../Node/LLMNode/index.js'; +import { StartNode } from '../Node/StartNode/index.js'; +import { NodesPanel } from '../NodePanel/index.js'; const yamlContent = ` - id: 1 @@ -233,7 +236,7 @@ export const FlowWithPanel = () => { return ( -
+
diff --git a/web/packages/magent-flow/src/components/Node/AgentNode/index.tsx b/web/packages/magent-flow/src/components/Node/AgentNode/index.tsx index 5e25a3f..5ae7932 100644 --- a/web/packages/magent-flow/src/components/Node/AgentNode/index.tsx +++ b/web/packages/magent-flow/src/components/Node/AgentNode/index.tsx @@ -1,10 +1,10 @@ -import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper'; -import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable'; -import { ReferenceForm } from '@/components/ReferenceForm'; -import { NodeDataType } from '@/interfaces/flow'; -import { useFlowStore } from '@/stores/useFlowStore'; -import React from 'react'; -import { NodeWrapper } from '../NodeWrapper'; +import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper/index.js'; +import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; +import { ReferenceForm } from '@/components/ReferenceForm/index.js'; +import type { NodeDataType } from '@/interfaces/flow.js'; +import { useFlowStore } from '@/stores/useFlowStore.js'; + +import { NodeWrapper } from '../NodeWrapper/index.js'; type Props = { data: NodeDataType; diff --git a/web/packages/magent-flow/src/components/Node/CommonNode/index.tsx b/web/packages/magent-flow/src/components/Node/CommonNode/index.tsx index 6377ffc..a2628f6 100644 --- a/web/packages/magent-flow/src/components/Node/CommonNode/index.tsx +++ b/web/packages/magent-flow/src/components/Node/CommonNode/index.tsx @@ -1,7 +1,9 @@ -import { NodeDataType } from '@/interfaces/flow'; import { Collapse } from 'antd'; import React from 'react'; -import { NodeWrapper } from '../NodeWrapper'; + +import type { NodeDataType } from '@/interfaces/flow.js'; + +import { NodeWrapper } from '../NodeWrapper/index.js'; type Props = { data: NodeDataType; diff --git a/web/packages/magent-flow/src/components/Node/EndNode/index.tsx b/web/packages/magent-flow/src/components/Node/EndNode/index.tsx index 8b3cf8f..a80f0f7 100644 --- a/web/packages/magent-flow/src/components/Node/EndNode/index.tsx +++ b/web/packages/magent-flow/src/components/Node/EndNode/index.tsx @@ -1,9 +1,10 @@ -import { ReferenceForm } from '@/components/ReferenceForm'; -import { NodeDataType } from '@/interfaces/flow'; -import { useFlowStore } from '@/stores/useFlowStore'; import { Collapse } from 'antd'; -import React from 'react'; -import { NodeWrapper } from '../NodeWrapper'; + +import { ReferenceForm } from '@/components/ReferenceForm/index.js'; +import type { NodeDataType } from '@/interfaces/flow.js'; +import { useFlowStore } from '@/stores/useFlowStore.js'; + +import { NodeWrapper } from '../NodeWrapper/index.js'; type Props = { data: NodeDataType; diff --git a/web/packages/magent-flow/src/components/Node/IfElseNode/index.tsx b/web/packages/magent-flow/src/components/Node/IfElseNode/index.tsx index e9c3924..06ae870 100644 --- a/web/packages/magent-flow/src/components/Node/IfElseNode/index.tsx +++ b/web/packages/magent-flow/src/components/Node/IfElseNode/index.tsx @@ -1,10 +1,11 @@ -import { SelectInNode } from '@/components/AIBasic/SelectInNode'; -import { ReferenceSelect } from '@/components/ReferenceSelect'; -import { NodeDataType } from '@/interfaces/flow'; -import { useFlowStore } from '@/stores/useFlowStore'; import { Form } from 'antd'; -import React from 'react'; -import { NodeWrapper } from '../NodeWrapper'; + +import { SelectInNode } from '@/components/AIBasic/SelectInNode/index.js'; +import { ReferenceSelect } from '@/components/ReferenceSelect/index.js'; +import type { NodeDataType } from '@/interfaces/flow.js'; +import { useFlowStore } from '@/stores/useFlowStore.js'; + +import { NodeWrapper } from '../NodeWrapper/index.js'; type Props = { data: NodeDataType; diff --git a/web/packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx b/web/packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx index 8a9a027..076b3c9 100644 --- a/web/packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx +++ b/web/packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx @@ -1,13 +1,14 @@ -import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper'; -import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable'; -import { ReferenceForm } from '@/components/ReferenceForm'; -import { NodeDataType } from '@/interfaces/flow'; -import { useFlowStore } from '@/stores/useFlowStore'; -import { useKnowledgeStore } from '@/stores/useKnowledgeStore'; import { PlusOutlined } from '@ant-design/icons'; import { Button, Modal } from 'antd'; -import React from 'react'; -import { NodeWrapper } from '../NodeWrapper'; + +import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper/index.js'; +import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; +import { ReferenceForm } from '@/components/ReferenceForm/index.js'; +import type { NodeDataType } from '@/interfaces/flow.js'; +import { useFlowStore } from '@/stores/useFlowStore.js'; +import { useKnowledgeStore } from '@/stores/useKnowledgeStore.js'; + +import { NodeWrapper } from '../NodeWrapper/index.js'; type Props = { data: NodeDataType; diff --git a/web/packages/magent-flow/src/components/Node/LLMNode/index.tsx b/web/packages/magent-flow/src/components/Node/LLMNode/index.tsx index f736768..d01e0f7 100644 --- a/web/packages/magent-flow/src/components/Node/LLMNode/index.tsx +++ b/web/packages/magent-flow/src/components/Node/LLMNode/index.tsx @@ -1,15 +1,17 @@ -import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper'; -import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable'; -import PromptEditor from '@/components/AIBasic/PromptEditor'; -import { SelectInNode } from '@/components/AIBasic/SelectInNode'; -import { ReferenceForm } from '@/components/ReferenceForm'; -import { NodeDataType } from '@/interfaces/flow'; -import { useFlowStore } from '@/stores/useFlowStore'; -import { useModelStore } from '@/stores/useModelStore'; import { BarsOutlined } from '@ant-design/icons'; import { Button, InputNumber, Popover } from 'antd'; -import React, { useState } from 'react'; -import { NodeWrapper } from '../NodeWrapper'; +import { useState } from 'react'; + +import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper/index.js'; +import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; +import PromptEditor from '@/components/AIBasic/PromptEditor/index.js'; +import { SelectInNode } from '@/components/AIBasic/SelectInNode/index.js'; +import { ReferenceForm } from '@/components/ReferenceForm/index.js'; +import type { NodeDataType } from '@/interfaces/flow.js'; +import { useFlowStore } from '@/stores/useFlowStore.js'; +import { useModelStore } from '@/stores/useModelStore.js'; + +import { NodeWrapper } from '../NodeWrapper/index.js'; type Props = { data: NodeDataType; diff --git a/web/packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx b/web/packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx index e85322e..71d7168 100644 --- a/web/packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx +++ b/web/packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx @@ -1,7 +1,8 @@ -import { classNames } from '@/utils/basic'; import { Popover, Tag } from 'antd'; import React from 'react'; +import { classNames } from '@/utils/basic.js'; + export enum RunStatusEnum { Success = 'success', Processing = 'processing', diff --git a/web/packages/magent-flow/src/components/Node/NodeWrapper/index.tsx b/web/packages/magent-flow/src/components/Node/NodeWrapper/index.tsx index 2d6381b..5800c27 100644 --- a/web/packages/magent-flow/src/components/Node/NodeWrapper/index.tsx +++ b/web/packages/magent-flow/src/components/Node/NodeWrapper/index.tsx @@ -2,8 +2,8 @@ import { Handle, Position } from '@xyflow/react'; import { Space } from 'antd'; import React from 'react'; -import type { NodeDataType } from '@/interfaces/flow'; -import { classNames } from '@/utils'; +import type { NodeDataType } from '@/interfaces/flow.js'; +import { classNames } from '@/utils/index.js'; type Props = { data: NodeDataType; diff --git a/web/packages/magent-flow/src/components/Node/StartNode/index.tsx b/web/packages/magent-flow/src/components/Node/StartNode/index.tsx index 555da9c..4c6a425 100644 --- a/web/packages/magent-flow/src/components/Node/StartNode/index.tsx +++ b/web/packages/magent-flow/src/components/Node/StartNode/index.tsx @@ -1,8 +1,9 @@ -import { VariableForm } from '@/components/VariableForm'; -import { NodeDataType } from '@/interfaces/flow'; import { Collapse } from 'antd'; -import React from 'react'; -import { NodeWrapper } from '../NodeWrapper'; + +import { VariableForm } from '@/components/VariableForm/index.js'; +import type { NodeDataType } from '@/interfaces/flow.js'; + +import { NodeWrapper } from '../NodeWrapper/index.js'; type Props = { data: NodeDataType; diff --git a/web/packages/magent-flow/src/components/NodePanel/index.tsx b/web/packages/magent-flow/src/components/NodePanel/index.tsx index d97e01b..b7eece2 100644 --- a/web/packages/magent-flow/src/components/NodePanel/index.tsx +++ b/web/packages/magent-flow/src/components/NodePanel/index.tsx @@ -1,7 +1,8 @@ -import { NodeDataType } from '@/interfaces/flow'; import { Input } from 'antd'; import React from 'react'; +import type { NodeDataType } from '@/interfaces/flow.js'; + interface NodesPanelProps { /** * @title 模板节点配置 diff --git a/web/packages/magent-flow/src/components/ReferenceForm/index.tsx b/web/packages/magent-flow/src/components/ReferenceForm/index.tsx index e68591f..d2a1aa5 100644 --- a/web/packages/magent-flow/src/components/ReferenceForm/index.tsx +++ b/web/packages/magent-flow/src/components/ReferenceForm/index.tsx @@ -2,10 +2,10 @@ import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; import { Button, Form, Input, Space } from 'antd'; import React, { useEffect } from 'react'; -import type { BasicSchema, NodeType } from '@/interfaces/flow'; +import type { BasicSchema, NodeType } from '@/interfaces/flow.js'; -import { CollapseWrapper } from '../AIBasic/CollapseWrapper'; -import { ReferenceSelect } from '../ReferenceSelect'; +import { CollapseWrapper } from '../AIBasic/CollapseWrapper/index.js'; +import { ReferenceSelect } from '../ReferenceSelect/index.js'; export interface RefrenceFormProps { label: string; diff --git a/web/packages/magent-flow/src/components/ReferenceSelect/index.tsx b/web/packages/magent-flow/src/components/ReferenceSelect/index.tsx index 04c1991..28540cc 100644 --- a/web/packages/magent-flow/src/components/ReferenceSelect/index.tsx +++ b/web/packages/magent-flow/src/components/ReferenceSelect/index.tsx @@ -1,7 +1,8 @@ import { Input } from 'antd'; import React from 'react'; -import { CascaderInNode } from '../AIBasic/CascaderInNode'; -import { SelectInNode } from '../AIBasic/SelectInNode'; + +import { CascaderInNode } from '../AIBasic/CascaderInNode/index.js'; +import { SelectInNode } from '../AIBasic/SelectInNode/index.js'; export const ReferenceSelect = (props: { value?: { diff --git a/web/packages/magent-flow/src/components/VariableForm/index.tsx b/web/packages/magent-flow/src/components/VariableForm/index.tsx index 94a783e..eb70954 100644 --- a/web/packages/magent-flow/src/components/VariableForm/index.tsx +++ b/web/packages/magent-flow/src/components/VariableForm/index.tsx @@ -6,9 +6,9 @@ import { import { Button, Checkbox, Collapse, Form, Input, Space } from 'antd'; import React, { useEffect } from 'react'; -import type { BasicSchema } from '@/interfaces/flow'; +import type { BasicSchema } from '@/interfaces/flow.js'; -import { SelectInNode } from '../AIBasic/SelectInNode'; +import { SelectInNode } from '../AIBasic/SelectInNode/index.js'; export interface VariableFormProps { label: string; diff --git a/web/packages/magent-flow/src/index.ts b/web/packages/magent-flow/src/index.ts index dc5c313..e6d7f38 100644 --- a/web/packages/magent-flow/src/index.ts +++ b/web/packages/magent-flow/src/index.ts @@ -1,8 +1,8 @@ -export { default as Flow } from './components/Flow'; -export { FlowWithPanel } from './components/FlowWithPanel'; -export { FormSchema } from './FormSchema'; -export { RefForm } from './RefForm'; -export { SchemaConfigForm } from './SchemaConfigForm'; -export { StartNode } from './spec/node'; +export { default as Flow } from './components/Flow/index.js'; +export { FlowWithPanel } from './components/FlowWithPanel/index.js'; +export { FormSchema } from './FormSchema/index.js'; +export { RefForm } from './RefForm/index.js'; +export { SchemaConfigForm } from './SchemaConfigForm/index.js'; +export { StartNode } from './spec/node.js'; export * from './utils/index.js'; import './tailwind.out.css'; diff --git a/web/packages/magent-flow/src/spec/node.ts b/web/packages/magent-flow/src/spec/node.ts index 3994e02..5b01977 100644 --- a/web/packages/magent-flow/src/spec/node.ts +++ b/web/packages/magent-flow/src/spec/node.ts @@ -1,11 +1,12 @@ -import { +import type { NodeDataConfigType, NodeDataMetaType, NodeDataType, - NodeTypeEnum, -} from '@/interfaces/flow'; -import { FormSchema } from './FormSchema'; -import { UUID } from './uuid'; +} from '@/interfaces/flow.js'; +import { NodeTypeEnum } from '@/interfaces/flow.js'; + +import { FormSchema } from './FormSchema/index.js'; +import { UUID } from './uuid.js'; // 不同类型的节点的基础类 // diff --git a/web/packages/magent-flow/src/stores/useFlowStore.ts b/web/packages/magent-flow/src/stores/useFlowStore.ts index f175086..0a7839e 100644 --- a/web/packages/magent-flow/src/stores/useFlowStore.ts +++ b/web/packages/magent-flow/src/stores/useFlowStore.ts @@ -14,8 +14,8 @@ import { addEdge, applyEdgeChanges, applyNodeChanges } from '@xyflow/react'; import { cloneDeep } from 'lodash'; import { create } from 'zustand'; -import type { NodeType } from '@/interfaces/flow'; -import { cleanEdges, getNodeId } from '@/utils/reactflowUtils'; +import type { NodeType } from '@/interfaces/flow.js'; +import { cleanEdges, getNodeId } from '@/utils/reactflowUtils.js'; interface AdjacencyList { [key: number]: number[]; diff --git a/web/packages/magent-flow/src/stores/useShortcutsStore.ts b/web/packages/magent-flow/src/stores/useShortcutsStore.ts index 78e3a3f..a7044ab 100644 --- a/web/packages/magent-flow/src/stores/useShortcutsStore.ts +++ b/web/packages/magent-flow/src/stores/useShortcutsStore.ts @@ -1,6 +1,6 @@ import { create } from 'zustand'; -import { defaultShortcuts } from '@/constants/constant'; +import { defaultShortcuts } from '@/constants/constant.js'; export type shortcutsStoreType = { updateUniqueShortcut: (name: string, combination: string) => void; diff --git a/web/packages/magent-flow/src/stores/useUndoRedoStore.ts b/web/packages/magent-flow/src/stores/useUndoRedoStore.ts index 401c90b..5e9da9a 100644 --- a/web/packages/magent-flow/src/stores/useUndoRedoStore.ts +++ b/web/packages/magent-flow/src/stores/useUndoRedoStore.ts @@ -2,7 +2,7 @@ import type { Edge, Node } from '@xyflow/react'; import { cloneDeep } from 'lodash'; import { create } from 'zustand'; -import { useFlowStore } from './useFlowStore'; +import { useFlowStore } from './useFlowStore.js'; interface FlowRedoUndoStoreType { undo: () => void; diff --git a/web/packages/magent-flow/src/utils/basic.ts b/web/packages/magent-flow/src/utils/basic.ts index a1db376..439133f 100644 --- a/web/packages/magent-flow/src/utils/basic.ts +++ b/web/packages/magent-flow/src/utils/basic.ts @@ -3,6 +3,8 @@ export function classNames(...classes: Array): string { } export function capitalizeFirstLetter(s: string) { - if (!s) return ''; + if (!s) { + return ''; + } return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); } diff --git a/web/packages/magent-flow/src/utils/index.tsx b/web/packages/magent-flow/src/utils/index.tsx index e1ad5ae..ec0f1b7 100644 --- a/web/packages/magent-flow/src/utils/index.tsx +++ b/web/packages/magent-flow/src/utils/index.tsx @@ -1,2 +1,2 @@ -export * from './basic'; -export * from './reactflowUtils'; +export * from './basic.js'; +export * from './reactflowUtils.js'; diff --git a/web/packages/magent-flow/src/utils/reactflowUtils.ts b/web/packages/magent-flow/src/utils/reactflowUtils.ts index 07816ba..4760dbc 100644 --- a/web/packages/magent-flow/src/utils/reactflowUtils.ts +++ b/web/packages/magent-flow/src/utils/reactflowUtils.ts @@ -1,9 +1,9 @@ -import { Edge } from '@xyflow/react'; +import type { Edge } from '@xyflow/react'; import { cloneDeep } from 'lodash'; import { v4 } from 'uuid'; export function cleanEdges(nodes: any[], edges: Edge[]) { - let newEdges = cloneDeep(edges); + const newEdges = cloneDeep(edges); return newEdges; } From 134e1f8b1192fb0694527d57477587adb80e8992 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 27 Aug 2024 15:20:15 +0800 Subject: [PATCH 03/78] feat(ui): add flow page --- .npmrc | 2 + web/ui/config/routes.ts | 4 + web/ui/package.json | 1 + web/ui/src/modules/app.module.ts | 2 + ...bution.ts => debug-drawer-contribution.ts} | 2 +- web/ui/src/views/agent-dev/module.ts | 4 +- .../src/views/agent-flow/agent-flow-view.tsx | 77 ++++++++++ web/ui/src/views/agent-flow/flow-dev-view.tsx | 72 ++++++++++ web/ui/src/views/agent-flow/index.less | 131 ++++++++++++++++++ web/ui/src/views/agent-flow/index.tsx | 1 + web/ui/src/views/agent-flow/module.ts | 17 +++ web/ui/src/views/agent-flow/protocol.ts | 5 + web/ui/src/views/agent-flow/utils.ts | 34 +++++ web/ui/src/views/agents/view.tsx | 6 +- 14 files changed, 352 insertions(+), 6 deletions(-) rename web/ui/src/views/agent-dev/{debug-contribution.ts => debug-drawer-contribution.ts} (75%) create mode 100644 web/ui/src/views/agent-flow/agent-flow-view.tsx create mode 100644 web/ui/src/views/agent-flow/flow-dev-view.tsx create mode 100644 web/ui/src/views/agent-flow/index.less create mode 100644 web/ui/src/views/agent-flow/index.tsx create mode 100644 web/ui/src/views/agent-flow/module.ts create mode 100644 web/ui/src/views/agent-flow/protocol.ts create mode 100644 web/ui/src/views/agent-flow/utils.ts diff --git a/.npmrc b/.npmrc index 4b9b305..0730e0d 100644 --- a/.npmrc +++ b/.npmrc @@ -4,3 +4,5 @@ save-workspace-protocol=rolling # pnpm deploy workaround https://github.com/pnpm/pnpm/issues/6437#issuecomment-1549409913 dedupe-peer-dependents=false + +link-workspace-packages=deep diff --git a/web/ui/config/routes.ts b/web/ui/config/routes.ts index a7753ac..e28e0db 100644 --- a/web/ui/config/routes.ts +++ b/web/ui/config/routes.ts @@ -30,6 +30,10 @@ export default [ path: '/agent/:agentId/dev', slot: 'magent-agent-dev-slot', }, + { + path: '/agent/:agentId/flow', + slot: 'magent-agent-flow-dev-slot', + }, ], }, ]; diff --git a/web/ui/package.json b/web/ui/package.json index 4d215ea..45fc42a 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -26,6 +26,7 @@ "@difizen/libro-jupyter": "^0.2.1", "@difizen/libro-lab": "^0.2.1", "@difizen/libro-markdown": "^0.2.1", + "@difizen/magent-flow": "workspace:^", "@difizen/mana-app": "^0.1.8", "@difizen/mana-react": "^0.1.8", "@rjsf/antd": "^5.18.2", diff --git a/web/ui/src/modules/app.module.ts b/web/ui/src/modules/app.module.ts index 8e58b42..61bcbeb 100644 --- a/web/ui/src/modules/app.module.ts +++ b/web/ui/src/modules/app.module.ts @@ -2,6 +2,7 @@ import { ManaModule } from '@difizen/mana-app'; import { AgentConfigViewModule } from '../views/agent-config/index.js'; import { AgentChatModule } from '../views/agent-dev/index.js'; +import { AgentFlowModule } from '../views/agent-flow/module.js'; import { AgentsPageModule } from '../views/agents/index.js'; import { ChatViewModule } from '../views/chat/module.js'; import { KnowledgePageModule } from '../views/knowledge/module.js'; @@ -39,6 +40,7 @@ export const AppBaseModule = new ManaModule() KnowledgePageModule, AgentConfigViewModule, PortalsModule, + AgentFlowModule, ); export default AppBaseModule; diff --git a/web/ui/src/views/agent-dev/debug-contribution.ts b/web/ui/src/views/agent-dev/debug-drawer-contribution.ts similarity index 75% rename from web/ui/src/views/agent-dev/debug-contribution.ts rename to web/ui/src/views/agent-dev/debug-drawer-contribution.ts index 8fd6553..60e2843 100644 --- a/web/ui/src/views/agent-dev/debug-contribution.ts +++ b/web/ui/src/views/agent-dev/debug-drawer-contribution.ts @@ -3,7 +3,7 @@ import { ModalContribution, singleton } from '@difizen/mana-app'; import { DebugModal } from './debug-modal.js'; @singleton({ contrib: [ModalContribution] }) -export class DebugContribution implements ModalContribution { +export class DebugDrawerContribution implements ModalContribution { registerModal() { return DebugModal; } diff --git a/web/ui/src/views/agent-dev/module.ts b/web/ui/src/views/agent-dev/module.ts index c03a39f..e62c2b7 100644 --- a/web/ui/src/views/agent-dev/module.ts +++ b/web/ui/src/views/agent-dev/module.ts @@ -3,13 +3,13 @@ import { createSlotPreference, ManaModule } from '@difizen/mana-app'; import { AgentConfigViewModule } from '../agent-config/module.js'; import { AgentView, slot as ChatSlot } from './chat-view.js'; -import { DebugContribution } from './debug-contribution.js'; +import { DebugDrawerContribution } from './debug-drawer-contribution.js'; import { AgentDevView, slot as DevSlot } from './dev-view.js'; export const AgentChatModule = ManaModule.create() .register( AgentView, - DebugContribution, + DebugDrawerContribution, createSlotPreference({ slot: ChatSlot, view: AgentView, diff --git a/web/ui/src/views/agent-flow/agent-flow-view.tsx b/web/ui/src/views/agent-flow/agent-flow-view.tsx new file mode 100644 index 0000000..d0f82f6 --- /dev/null +++ b/web/ui/src/views/agent-flow/agent-flow-view.tsx @@ -0,0 +1,77 @@ +import { SaveOutlined } from '@ant-design/icons'; +import { FlowWithPanel } from '@difizen/magent-flow'; +import { + BaseView, + ViewInstance, + inject, + prop, + useInject, + view, + ViewOption, + transient, +} from '@difizen/mana-app'; +import { Flex } from 'antd'; +import { forwardRef } from 'react'; + +import { AgentManager } from '../../modules/agent/index.js'; +import type { AgentModel } from '../../modules/agent/index.js'; + +import './index.less'; + +const viewId = 'magent-agent-flow'; + +const AgentFlowComponent = forwardRef( + function AgentConfigViewComponent(props, ref) { + const instance = useInject(ViewInstance); + + return ( +
+ +
+ ); + }, +); + +export interface AgentConfigViewOption { + agentId: string; +} +@transient() +@view(viewId) +export class AgentFlowView extends BaseView { + agentId: string; + override view = AgentFlowComponent; + + @prop() agent: AgentModel; + protected agentManager: AgentManager; + constructor( + @inject(ViewOption) option: AgentConfigViewOption, + @inject(AgentManager) agentManager: AgentManager, + ) { + super(); + this.agentId = option.agentId; + this.agentManager = agentManager; + this.initAgent(option.agentId); + } + + get modelOptions() { + // TODO 大模型optios列表和对应存取值要怎么取? + return ( + this.agent?.llm?.model_name?.map((item) => { + return { + label: item, + value: item, + }; + }) || [] + ); + } + + protected initAgent = (agentId = this.agentId) => { + if (agentId) { + const agent = this.agentManager.getOrCreateAgent({ id: agentId }); + agent.fetchInfo(); + this.agent = agent; + return agent; + } + return undefined; + }; +} diff --git a/web/ui/src/views/agent-flow/flow-dev-view.tsx b/web/ui/src/views/agent-flow/flow-dev-view.tsx new file mode 100644 index 0000000..a892ac4 --- /dev/null +++ b/web/ui/src/views/agent-flow/flow-dev-view.tsx @@ -0,0 +1,72 @@ +import { ViewRender } from '@difizen/mana-app'; +import { ViewInstance, singleton, useInject, view } from '@difizen/mana-app'; +import { BoxPanel } from '@difizen/mana-react'; +import { forwardRef, useEffect } from 'react'; +import { useMatch } from 'react-router-dom'; + +import type { AgentConfigManager } from '../../modules/agent/agent-config-manager.js'; +import { AgentView } from '../agent-dev/chat-view.js'; + +import { AgentFlowView } from './agent-flow-view.js'; + +import './index.less'; + +const viewId = 'magent-agent-flow-dev'; +export const slot = `${viewId}-slot`; + +const AgentFlowDevComponent = forwardRef( + function AgentsViewComponent(props, ref) { + const instance = useInject(ViewInstance); + const match = useMatch('/agent/:agentId/flow'); + const agentId = match?.params?.agentId; + instance.agentId = agentId; + + useEffect(() => { + instance.openChat(instance.sessions?.active); + }, [instance, instance.sessions?.active]); + + return ( +
+ + {instance.agentFlow && } + {/* + {instance.agentFlow && } + + +
+

预览

+
+
+ {instance.chat && } +
+
*/} +
+
+ ); + }, +); + +@singleton() +@view(viewId) +export class AgentFlowDevView extends AgentView { + protected agentConfigManager: AgentConfigManager; + + agentFlow?: AgentFlowView; + + override view = AgentFlowDevComponent; + + protected override initialize() { + super.initialize(); + this.initAgentFlowView(); + } + + protected initAgentFlowView = async () => { + if (!this.agentId) { + return; + } + const agentFlow = await this.viewManager.getOrCreateView(AgentFlowView, { + agentId: this.agentId, + }); + this.agentFlow = agentFlow; + }; +} diff --git a/web/ui/src/views/agent-flow/index.less b/web/ui/src/views/agent-flow/index.less new file mode 100644 index 0000000..e7c505e --- /dev/null +++ b/web/ui/src/views/agent-flow/index.less @@ -0,0 +1,131 @@ +.magent-agent-chat-layout { + height: 100%; + + &-container { + gap: 16px; + box-sizing: border-box; + padding: 12px 24px; + } + + &-history { + width: 260px; + } + + &-chat { + max-width: calc(100% - 276px); + } +} + +.magent-agent-flow-dev-layout { + height: 100%; + width: 100%; +} + +.magent-agent-dev-layout { + height: 100%; + + &-container { + gap: 16px; + box-sizing: border-box; + padding: 12px 24px; + } + + &-config { + width: 55%; + } + + &-chat-dev { + height: 100%; + min-width: 520px; + width: 520px; + background-color: var(--mana-color-bg-container); + border-radius: 8px; + + &-header { + padding: 0 24px; + height: 64px; + border-bottom: 1px solid var(--mana-color-border); + display: flex; + align-items: center; + justify-content: space-between; + + h3 { + margin: 0; + } + } + + &-content { + height: calc(100% - 64px); + } + } +} + +.magent-debug { + width: 622px; +} + +.magent-debug-header { + background-color: #f7f7fa; + border-bottom: 1px solid rgba(29, 28, 35, 8%); + padding: 16px 24px; +} + +.magent-select-container { + padding: 24px 24px 4px; + width: 100%; + + :global { + background-color: rgba(139, 139, 149, 15%); + color: rgba(75, 74, 88, 100%); + } +} + +.magent-summary-container { + padding: 16px 24px 24px; + position: relative; + width: 100%; +} + +.magent-summary-title-container { + margin-bottom: 16px; +} + +.magent-summary-title-data { + color: #1d1c23; + font-size: 14px; + font-weight: 600; + margin-right: 8px; +} + +.magent-des-item { + display: flex; + font-size: 13px; + line-height: 22px; + text-align: left; +} + +.magent-des-key { + color: rgba(29, 28, 35, 35%); + margin-right: 4px; +} + +.magent-des-value { + color: rgba(29, 28, 35, 80%); +} + +.magent-des-icon { + margin-left: 6px; + cursor: pointer; +} + +.magent-agent-flow { + height: 100%; + width: 100%; + overflow-y: auto; + display: flex; + justify-items: center; + flex-direction: column; + background-color: var(--mana-color-bg-container); + box-sizing: border-box; + border-radius: 8px; +} diff --git a/web/ui/src/views/agent-flow/index.tsx b/web/ui/src/views/agent-flow/index.tsx new file mode 100644 index 0000000..fd3c604 --- /dev/null +++ b/web/ui/src/views/agent-flow/index.tsx @@ -0,0 +1 @@ +export * from './module.js'; diff --git a/web/ui/src/views/agent-flow/module.ts b/web/ui/src/views/agent-flow/module.ts new file mode 100644 index 0000000..75d6ef5 --- /dev/null +++ b/web/ui/src/views/agent-flow/module.ts @@ -0,0 +1,17 @@ +import { createSlotPreference, ManaModule } from '@difizen/mana-app'; + +import { AgentConfigViewModule } from '../agent-config/module.js'; + +import { AgentFlowView } from './agent-flow-view.js'; +import { AgentFlowDevView, slot } from './flow-dev-view.js'; + +export const AgentFlowModule = ManaModule.create() + .register( + AgentFlowView, + AgentFlowDevView, + createSlotPreference({ + slot: slot, + view: AgentFlowDevView, + }), + ) + .dependOn(AgentConfigViewModule); diff --git a/web/ui/src/views/agent-flow/protocol.ts b/web/ui/src/views/agent-flow/protocol.ts new file mode 100644 index 0000000..d33e96b --- /dev/null +++ b/web/ui/src/views/agent-flow/protocol.ts @@ -0,0 +1,5 @@ +export const AgentLayoutSlots = { + history: 'magent-agent-chat-history', + config: 'magent-agent-dev-config', + chat: 'magent-agent-chat', +}; diff --git a/web/ui/src/views/agent-flow/utils.ts b/web/ui/src/views/agent-flow/utils.ts new file mode 100644 index 0000000..e05cbde --- /dev/null +++ b/web/ui/src/views/agent-flow/utils.ts @@ -0,0 +1,34 @@ +function copyFallback(string: string) { + function handler(event: ClipboardEvent) { + const clipboardData = event.clipboardData || (window as any).clipboardData; + clipboardData.setData('text/plain', string); + event.preventDefault(); + document.removeEventListener('copy', handler, true); + } + + document.addEventListener('copy', handler, true); + document.execCommand('copy'); +} +// 复制到剪贴板 +export const copy2clipboard = (string: string) => { + navigator.permissions + .query({ + name: 'clipboard-write' as any, + }) + .then((result) => { + if (result.state === 'granted' || result.state === 'prompt') { + if (window.navigator && window.navigator.clipboard) { + window.navigator.clipboard.writeText(string); + } else { + console.warn('navigator is not exist'); + } + } else { + console.warn('浏览器权限不允许复制'); + copyFallback(string); + } + return; + }) + .catch(() => { + // + }); +}; diff --git a/web/ui/src/views/agents/view.tsx b/web/ui/src/views/agents/view.tsx index a4220a2..e79ce0a 100644 --- a/web/ui/src/views/agents/view.tsx +++ b/web/ui/src/views/agents/view.tsx @@ -17,7 +17,7 @@ import './index.less'; import { AgentIcon } from '../../modules/agent/agent-icon.js'; import { AgentMarket } from '../../modules/agent/agent-market.js'; -import { AgentCreateModal, agentCreateModalId } from './modal/create.js'; +import { AgentCreateModal } from './modal/create.js'; const viewId = 'magent-agents'; export const slot = `${viewId}-slot`; @@ -65,7 +65,7 @@ const AgentsViewComponent = forwardRef( ))}
- {/*
+
-
*/} +
); }, From d910bb63d6bfacba413f0ad522b71ddbb5556b13 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 27 Aug 2024 19:05:24 +0800 Subject: [PATCH 04/78] feat(ui): add agent & workflow creation api --- .../src/magent_ui/routers/agents/router.py | 3 +++ .../magent-ui/src/magent_ui/routers/main.py | 2 ++ .../magent_ui/routers/workflow/__init__.py | 0 .../src/magent_ui/routers/workflow/router.py | 20 +++++++++++++++++++ 4 files changed, 25 insertions(+) create mode 100644 packages/magent-ui/src/magent_ui/routers/workflow/__init__.py create mode 100644 packages/magent-ui/src/magent_ui/routers/workflow/router.py diff --git a/packages/magent-ui/src/magent_ui/routers/agents/router.py b/packages/magent-ui/src/magent_ui/routers/agents/router.py index aebbe3e..3647360 100644 --- a/packages/magent-ui/src/magent_ui/routers/agents/router.py +++ b/packages/magent-ui/src/magent_ui/routers/agents/router.py @@ -26,6 +26,9 @@ async def get_agent_detail(agent_id): async def update_agent(agent_id, agent: AgentDTO): return AgentService.update_agent(agent) +@router.post("/agents", response_model=AgentDTO) +async def create_agent(agent: AgentDTO): + return AgentService.create_agent(agent) class MessageSenderType(enum.Enum): AI = "ai" diff --git a/packages/magent-ui/src/magent_ui/routers/main.py b/packages/magent-ui/src/magent_ui/routers/main.py index 76855a7..3d59900 100644 --- a/packages/magent-ui/src/magent_ui/routers/main.py +++ b/packages/magent-ui/src/magent_ui/routers/main.py @@ -5,6 +5,7 @@ from magent_ui.routers.sessions.router import sessions_router from magent_ui.routers.tools.router import tools_router from magent_ui.routers.resource.router import resource_router +from magent_ui.routers.workflow.router import workflow_router api_router = APIRouter() @@ -14,3 +15,4 @@ api_router.include_router(sessions_router, prefix="/v1", tags=["session"]) api_router.include_router(tools_router, prefix="/v1", tags=["tool"]) api_router.include_router(resource_router, prefix="/v1", tags=["resource"]) +api_router.include_router(workflow_router, prefix="/v1", tags=["workflow"]) diff --git a/packages/magent-ui/src/magent_ui/routers/workflow/__init__.py b/packages/magent-ui/src/magent_ui/routers/workflow/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/packages/magent-ui/src/magent_ui/routers/workflow/router.py b/packages/magent-ui/src/magent_ui/routers/workflow/router.py new file mode 100644 index 0000000..2235c83 --- /dev/null +++ b/packages/magent-ui/src/magent_ui/routers/workflow/router.py @@ -0,0 +1,20 @@ +from fastapi import APIRouter +from agentuniverse_product.service.workflow_service.workflow_service import WorkflowService +from agentuniverse_product.service.model.workflow_dto import WorkflowDTO + +router = APIRouter() +workflow_router = router + + +@router.get("/workflows/{workflow_id}", response_model=WorkflowDTO | None) +async def get_agent_detail(workflow_id): + return WorkflowService.get_workflow_detail(workflow_id) + + +@router.put("/workflows/{workflow_id}", response_model=WorkflowDTO | None) +async def update_agent(workflow_id, workflow: WorkflowDTO): + return WorkflowService.update_workflow(workflow) + +@router.post("/workflows", response_model=WorkflowDTO) +async def create_agent(workflow: WorkflowDTO): + return WorkflowService.create_workflow(workflow) From 05bab7a93eccd853b5b6a8edf141a4c357578fc6 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 27 Aug 2024 19:06:00 +0800 Subject: [PATCH 05/78] feat(ui): model icon & import path alias --- .../src/modules/model/model-icon/baichuan.svg | 1 + .../src/modules/model/model-icon/deepseek.svg | 1 + web/ui/src/modules/model/model-icon/ernie.svg | 1 + web/ui/src/modules/model/model-icon/index.tsx | 65 +++++++++++++++++ .../src/modules/model/model-icon/moonshot.svg | 1 + .../src/modules/model/model-icon/openai.svg | 5 ++ web/ui/src/modules/model/model-icon/qwen.svg | 12 ++++ .../components/model-selector/index.tsx | 22 +----- .../components/model-selector/logos.tsx | 69 ------------------- web/ui/src/views/agent-dev/debug-modal.tsx | 7 +- web/ui/tsconfig.json | 3 + web/ui/typings/index.d.ts | 1 + 12 files changed, 96 insertions(+), 92 deletions(-) create mode 100644 web/ui/src/modules/model/model-icon/baichuan.svg create mode 100644 web/ui/src/modules/model/model-icon/deepseek.svg create mode 100644 web/ui/src/modules/model/model-icon/ernie.svg create mode 100644 web/ui/src/modules/model/model-icon/index.tsx create mode 100644 web/ui/src/modules/model/model-icon/moonshot.svg create mode 100644 web/ui/src/modules/model/model-icon/openai.svg create mode 100644 web/ui/src/modules/model/model-icon/qwen.svg delete mode 100644 web/ui/src/views/agent-config/components/model-selector/logos.tsx diff --git a/web/ui/src/modules/model/model-icon/baichuan.svg b/web/ui/src/modules/model/model-icon/baichuan.svg new file mode 100644 index 0000000..ebd9800 --- /dev/null +++ b/web/ui/src/modules/model/model-icon/baichuan.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/ui/src/modules/model/model-icon/deepseek.svg b/web/ui/src/modules/model/model-icon/deepseek.svg new file mode 100644 index 0000000..658e9dd --- /dev/null +++ b/web/ui/src/modules/model/model-icon/deepseek.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/ui/src/modules/model/model-icon/ernie.svg b/web/ui/src/modules/model/model-icon/ernie.svg new file mode 100644 index 0000000..36ff641 --- /dev/null +++ b/web/ui/src/modules/model/model-icon/ernie.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/ui/src/modules/model/model-icon/index.tsx b/web/ui/src/modules/model/model-icon/index.tsx new file mode 100644 index 0000000..5532dfe --- /dev/null +++ b/web/ui/src/modules/model/model-icon/index.tsx @@ -0,0 +1,65 @@ +import { lazy, Suspense } from 'react'; + +import type { ModelMeta } from '@/modules/model/protocol.js'; + +const LazyIcon = (props: { loader: () => Promise }) => { + const Component = lazy(async () => { + const icon = await props.loader(); + return { default: () => }; + }); + return ( + }> + + + ); +}; + +export const DefaultLLMIcon = () => { + return ( + + + + ); +}; + +const match = (data: ModelMeta, name: string): boolean => { + if ( + data.id.toLowerCase().includes(name) || + data.nickname.toLowerCase().includes(name) || + data.model_name[0].toLowerCase().includes(name) + ) { + return true; + } + return false; +}; + +export const LLMIcon = (props: { data: ModelMeta }) => { + const { data } = props; + if (match(data, 'qwen')) { + return import('./qwen.svg')} />; + } + if (match(data, 'openai')) { + return import('./openai.svg')} />; + } + if (match(data, 'baichuan')) { + return import('./baichuan.svg')} />; + } + if (match(data, 'deepseek')) { + return import('./deepseek.svg')} />; + } + if (match(data, 'ernie')) { + return import('./ernie.svg')} />; + } + if (match(data, 'moonshot')) { + return import('./moonshot.svg')} />; + } + return ; +}; diff --git a/web/ui/src/modules/model/model-icon/moonshot.svg b/web/ui/src/modules/model/model-icon/moonshot.svg new file mode 100644 index 0000000..ac19383 --- /dev/null +++ b/web/ui/src/modules/model/model-icon/moonshot.svg @@ -0,0 +1 @@ + diff --git a/web/ui/src/modules/model/model-icon/openai.svg b/web/ui/src/modules/model/model-icon/openai.svg new file mode 100644 index 0000000..eea83cb --- /dev/null +++ b/web/ui/src/modules/model/model-icon/openai.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/web/ui/src/modules/model/model-icon/qwen.svg b/web/ui/src/modules/model/model-icon/qwen.svg new file mode 100644 index 0000000..b5dff55 --- /dev/null +++ b/web/ui/src/modules/model/model-icon/qwen.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/web/ui/src/views/agent-config/components/model-selector/index.tsx b/web/ui/src/views/agent-config/components/model-selector/index.tsx index 9d33d61..e177152 100644 --- a/web/ui/src/views/agent-config/components/model-selector/index.tsx +++ b/web/ui/src/views/agent-config/components/model-selector/index.tsx @@ -3,34 +3,16 @@ import { ViewInstance, useInject } from '@difizen/mana-app'; import { Button, Form, Select, Popover, Avatar, Slider } from 'antd'; import { forwardRef, useEffect } from 'react'; +import { LLMIcon } from '@/modules/model/model-icon/index.js'; + import { LLMManager } from '../../../../modules/model/llm-manager.js'; import type { ModelMeta } from '../../../../modules/model/protocol.js'; import type { AgentConfigView } from '../../view.js'; import './index.less'; -import { DefaultLogo, OpenAILogo, QwenLogo } from './logos.js'; const clsPrefix = 'agent-config-model-selector'; -const LLMIcon = (props: { data: ModelMeta }) => { - const { data } = props; - if ( - data.id.toLowerCase().includes('qwen') || - data.nickname.toLowerCase().includes('qwen') || - data.model_name[0].toLowerCase().includes('qwen') - ) { - return ; - } - if ( - data.id.toLowerCase().includes('openai') || - data.nickname.toLowerCase().includes('openai') || - data.model_name[0].toLowerCase().includes('openai') - ) { - return ; - } - return ; -}; - const ModelSelectorOption = (props: { model: ModelMeta; flat?: boolean }) => { const { model, flat } = props; return ( diff --git a/web/ui/src/views/agent-config/components/model-selector/logos.tsx b/web/ui/src/views/agent-config/components/model-selector/logos.tsx deleted file mode 100644 index 020aaed..0000000 --- a/web/ui/src/views/agent-config/components/model-selector/logos.tsx +++ /dev/null @@ -1,69 +0,0 @@ -export const OpenAILogo = () => { - return ( - - - - ); -}; - -export const QwenLogo = () => { - return ( - - - - - ); -}; - -export const MoonshotLogo = () => { - return ( - - - - ); -}; - -export const DefaultLogo = () => { - return ( - - - - ); -}; diff --git a/web/ui/src/views/agent-dev/debug-modal.tsx b/web/ui/src/views/agent-dev/debug-modal.tsx index 50d327b..d1a3066 100644 --- a/web/ui/src/views/agent-dev/debug-modal.tsx +++ b/web/ui/src/views/agent-dev/debug-modal.tsx @@ -7,8 +7,9 @@ import { Avatar } from 'antd'; import { Col, Drawer, Row, Select, Tree } from 'antd'; import { useState } from 'react'; +import { DefaultLLMIcon } from '@/modules/model/model-icon/index.js'; + import { DefaultToolIcon } from '../../modules/tool/tool-icon.js'; -import { DefaultLogo } from '../agent-config/components/model-selector/logos.js'; import { HumanIcon } from '../chat/components/message/human-message.js'; import type { ChatView } from '../chat/view.js'; @@ -45,10 +46,10 @@ export function DebugModalComponent({ children: invocationChain.map((item) => { let iconSrc = undefined; if (item.type === 'llm') { - iconSrc = ; + iconSrc = ; } if (item.type === 'agent') { - iconSrc = ; + iconSrc = ; } if (item.type === 'tool') { iconSrc = ; diff --git a/web/ui/tsconfig.json b/web/ui/tsconfig.json index df7da4f..1ac0e79 100644 --- a/web/ui/tsconfig.json +++ b/web/ui/tsconfig.json @@ -1,6 +1,9 @@ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + }, /* interop */ "allowJs": true, "allowSyntheticDefaultImports": true, diff --git a/web/ui/typings/index.d.ts b/web/ui/typings/index.d.ts index ad32997..adb8688 100644 --- a/web/ui/typings/index.d.ts +++ b/web/ui/typings/index.d.ts @@ -14,3 +14,4 @@ interface Pagination { } declare module '*.jpg'; +declare module '*.svg'; From 6c04d837db15270acdf41e56a8a8529241d39056 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 27 Aug 2024 19:41:28 +0800 Subject: [PATCH 06/78] feat(ui): performance of llm temperature slider --- web/ui/src/modules/agent/agent-model.ts | 11 +++-- web/ui/src/modules/model/llm-manager.ts | 19 +++++-- web/ui/src/modules/model/llm-model.ts | 3 +- .../components/model-selector/index.tsx | 49 ++++++++++++------- 4 files changed, 57 insertions(+), 25 deletions(-) diff --git a/web/ui/src/modules/agent/agent-model.ts b/web/ui/src/modules/agent/agent-model.ts index 1e2bb68..20215f8 100644 --- a/web/ui/src/modules/agent/agent-model.ts +++ b/web/ui/src/modules/agent/agent-model.ts @@ -3,6 +3,8 @@ import { inject, prop, transient } from '@difizen/mana-app'; import { AsyncModel } from '../../common/async-model.js'; import { AxiosClient } from '../axios-client/index.js'; import type { KnowledgeModelOption } from '../knowledge/protocol.js'; +import { LLMManager } from '../model/llm-manager.js'; +import type { LLMModel } from '../model/llm-model.js'; import type { ToolModelOption } from '../tool/index.js'; import { ToolManager } from '../tool/index.js'; @@ -40,6 +42,7 @@ export class AgentModel extends AsyncModel { axios: AxiosClient; // configManager: AgentConfigManager; + protected llmManager: LLMManager; id: string; @@ -53,7 +56,7 @@ export class AgentModel extends AsyncModel { description?: string; @prop() - llm?: LLMMeta; + llm?: LLMModel; @prop() prompt?: Prompt; @@ -79,12 +82,14 @@ export class AgentModel extends AsyncModel { constructor( @inject(AgentModelOption) option: AgentModelOption, @inject(AgentConfigManager) configManager: AgentConfigManager, + @inject(LLMManager) llmManager: LLMManager, @inject(AxiosClient) axios: AxiosClient, ) { super(); this.option = option; // this.configManager = configManager; this.axios = axios; + this.llmManager = llmManager; this.id = option.id; this.initialize(option); @@ -105,7 +110,7 @@ export class AgentModel extends AsyncModel { this.description = option.description; this.prompt = option.prompt ? new Prompt(option.prompt) : undefined; - this.llm = option.llm; + this.llm = option.llm ? this.llmManager.getOrCreate(option.llm) : option.llm; this.memory = option.memory ?? ''; this.planner = option.planner; this.knowledge = option.knowledge; @@ -139,7 +144,7 @@ export class AgentModel extends AsyncModel { avatar: this.avatar, description: this.description, prompt: this.prompt?.toMeta(), - llm: this.llm, + llm: this.llm?.toMeta(), planner: this.planner, tool: this.tool, memory: this.memory, diff --git a/web/ui/src/modules/model/llm-manager.ts b/web/ui/src/modules/model/llm-manager.ts index c0691e5..cf045fc 100644 --- a/web/ui/src/modules/model/llm-manager.ts +++ b/web/ui/src/modules/model/llm-manager.ts @@ -8,13 +8,14 @@ import { LLMModelFactory } from './protocol.js'; @singleton() export class LLMManager { + protected cache: Map = new Map(); @inject(LLMModelFactory) factory: LLMModelFactory; @inject(AxiosClient) axios: AxiosClient; @prop() models: LLMModel[] = []; - // defaultModel?: ModelMeta; + defaultModel?: LLMModel; protected getModelsMeta = async () => { const defaultValue: ModelMeta[] = []; @@ -27,10 +28,20 @@ export class LLMManager { updateModels = async () => { const metas = await this.getModelsMeta(); - this.models = metas.map((item) => this.factory(item)); + this.models = metas.map((item) => this.getOrCreate(item)); if (this.models.length > 0) { - const defaultLLMs = this.models[0]; - this.defaultModel = defaultLLMs.toSingleMeta(defaultLLMs.models[0]); + const defaultLLM = this.models[0]; + this.defaultModel = defaultLLM; } }; + + getOrCreate = (option: ModelMeta): LLMModel => { + const exist = this.cache.get(option.id); + if (exist) { + return exist; + } + const llm = this.factory(option); + this.cache.set(llm.id, llm); + return llm; + }; } diff --git a/web/ui/src/modules/model/llm-model.ts b/web/ui/src/modules/model/llm-model.ts index dfd2134..849346b 100644 --- a/web/ui/src/modules/model/llm-model.ts +++ b/web/ui/src/modules/model/llm-model.ts @@ -1,4 +1,4 @@ -import { inject, transient } from '@difizen/mana-app'; +import { inject, prop, transient } from '@difizen/mana-app'; import { LLMModelOption, type ModelMeta } from './protocol.js'; @@ -8,6 +8,7 @@ export class LLMModel { name: string; models: string[] = []; + @prop() temperature: number; protected configStr: string; diff --git a/web/ui/src/views/agent-config/components/model-selector/index.tsx b/web/ui/src/views/agent-config/components/model-selector/index.tsx index e177152..0a145d0 100644 --- a/web/ui/src/views/agent-config/components/model-selector/index.tsx +++ b/web/ui/src/views/agent-config/components/model-selector/index.tsx @@ -1,8 +1,11 @@ import { CaretDownOutlined } from '@ant-design/icons'; -import { ViewInstance, useInject } from '@difizen/mana-app'; +import { ViewInstance, useInject, useObserve } from '@difizen/mana-app'; +import type { SliderSingleProps } from 'antd'; import { Button, Form, Select, Popover, Avatar, Slider } from 'antd'; +import type { FC } from 'react'; import { forwardRef, useEffect } from 'react'; +import type { LLMModel } from '@/modules/model/llm-model.js'; import { LLMIcon } from '@/modules/model/model-icon/index.js'; import { LLMManager } from '../../../../modules/model/llm-manager.js'; @@ -35,6 +38,30 @@ const toKey = (model?: ModelMeta) => { return model.id + model.model_name[0]; }; +interface TemperatureSliderProps extends SliderSingleProps { + llm?: LLMModel; +} +const TemperatureSlider: FC = ( + props: TemperatureSliderProps, +) => { + const llm = useObserve(props.llm); + const temperature = llm?.temperature; + return ( + { + if (llm) { + llm.temperature = v; + } + }} + value={temperature === undefined ? 1 : temperature} + /> + ); +}; + export const ModelSelector = forwardRef( function ModelSelectorComponent(props, ref) { const instance = useInject(ViewInstance); @@ -55,11 +82,9 @@ export const ModelSelector = forwardRef( }, [modelManager]); const currentModel = metaModels.find( - (item) => modelMeta && toKey(item) === toKey(modelMeta), + (item) => modelMeta && toKey(item) === toKey(modelMeta.toMeta()), ); - const temperature = instance.agent.llm?.temperature; - return (
( onSelect={(v) => { const llm = metaModels.find((i) => toKey(i) === v); if (instance.agent.llm && llm) { - instance.agent.llm = llm; + instance.agent.llm = modelManager.getOrCreate(llm); } }} - value={toKey(instance.agent.llm)} + value={toKey(instance.agent.llm?.toMeta())} > {models.map((model) => ( @@ -96,17 +121,7 @@ export const ModelSelector = forwardRef( - { - if (instance.agent.llm) { - instance.agent.llm.temperature = v; - } - }} - value={temperature === undefined ? 1 : temperature} - /> +
From 09ce5905ad370baf289e2eaa3aba3a1d24e90d8a Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 27 Aug 2024 20:03:33 +0800 Subject: [PATCH 07/78] =?UTF-8?q?refactor(ui):=20use=20short=20reference?= =?UTF-8?q?=20paths=EF=BC=8Cand=20remove=20base=20module=20exports=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/modules/agent/agent-config-manager.ts | 5 ++-- web/ui/src/modules/agent/agent-config.ts | 13 +++++++---- web/ui/src/modules/agent/agent-icon.tsx | 3 ++- web/ui/src/modules/agent/agent-manager.ts | 6 ++--- web/ui/src/modules/agent/agent-market.ts | 4 ++-- web/ui/src/modules/agent/agent-model.ts | 11 +++++---- web/ui/src/modules/agent/index.ts | 6 ----- web/ui/src/modules/agent/module.ts | 2 -- web/ui/src/modules/app.module.ts | 12 +++++----- web/ui/src/modules/axios-client/client.ts | 2 +- web/ui/src/modules/axios-client/index.ts | 2 -- web/ui/src/modules/base-layout/index.ts | 1 - .../modules/chat-message/ai-message-item.ts | 2 +- .../modules/chat-message/chat-message-item.ts | 2 +- .../chat-message/chat-message-manager.ts | 2 +- .../chat-message/chat-message-model.ts | 4 ++-- web/ui/src/modules/chat-message/index.ts | 2 -- web/ui/src/modules/knowledge/index.ts | 4 ---- .../src/modules/knowledge/knowledge-icon.tsx | 2 +- .../modules/knowledge/knowledge-manager.ts | 6 ++--- .../src/modules/knowledge/knowledge-model.ts | 4 ++-- .../src/modules/knowledge/knowledge-space.ts | 4 ++-- web/ui/src/modules/session/index.ts | 3 --- web/ui/src/modules/session/session-manager.ts | 2 +- web/ui/src/modules/session/session-model.ts | 4 ++-- web/ui/src/modules/tool/index.ts | 6 ----- .../src/modules/tool/tool-config-manager.ts | 2 +- web/ui/src/modules/tool/tool-config.ts | 4 ++-- web/ui/src/modules/tool/tool-icon.tsx | 2 +- web/ui/src/modules/tool/tool-manager.ts | 6 ++--- web/ui/src/modules/tool/tool-model.ts | 4 ++-- web/ui/src/modules/tool/tool-space.ts | 4 ++-- .../components/model-selector/index.tsx | 4 ++-- .../agent-config/knowledge-modal/modal.tsx | 8 +++---- .../views/agent-config/tools-modal/modal.tsx | 8 +++---- web/ui/src/views/agent-config/view.tsx | 12 +++++----- web/ui/src/views/agent-dev/chat-view.tsx | 10 ++++---- web/ui/src/views/agent-dev/debug-modal.tsx | 2 +- web/ui/src/views/agent-dev/dev-view.tsx | 2 +- .../src/views/agent-flow/agent-flow-view.tsx | 23 ++++--------------- web/ui/src/views/agent-flow/flow-dev-view.tsx | 2 +- web/ui/src/views/agents/modal/create.tsx | 4 ++-- web/ui/src/views/agents/view.tsx | 4 ++-- .../chat/components/message/ai-message.tsx | 9 ++++---- .../chat/components/message/exchange.tsx | 2 +- .../chat/components/message/human-message.tsx | 5 ++-- .../views/chat/components/message/message.tsx | 10 ++++---- .../chat/components/message/peer-message.tsx | 11 +++++---- web/ui/src/views/chat/view.tsx | 21 ++++++++--------- web/ui/src/views/knowledge/module.ts | 2 +- web/ui/src/views/knowledge/view.tsx | 10 ++++---- .../sessions/conversation-list/index.tsx | 5 ++-- web/ui/src/views/sessions/view.tsx | 7 +++--- web/ui/src/views/tools/module.ts | 2 +- web/ui/src/views/tools/view.tsx | 4 ++-- 55 files changed, 137 insertions(+), 166 deletions(-) delete mode 100644 web/ui/src/modules/agent/index.ts delete mode 100644 web/ui/src/modules/axios-client/index.ts delete mode 100644 web/ui/src/modules/base-layout/index.ts delete mode 100644 web/ui/src/modules/chat-message/index.ts delete mode 100644 web/ui/src/modules/knowledge/index.ts delete mode 100644 web/ui/src/modules/session/index.ts delete mode 100644 web/ui/src/modules/tool/index.ts diff --git a/web/ui/src/modules/agent/agent-config-manager.ts b/web/ui/src/modules/agent/agent-config-manager.ts index 40f4352..d4c2ca9 100644 --- a/web/ui/src/modules/agent/agent-config-manager.ts +++ b/web/ui/src/modules/agent/agent-config-manager.ts @@ -1,12 +1,11 @@ import { inject, singleton } from '@difizen/mana-app'; -import { AxiosClient } from '../axios-client/index.js'; +import { AxiosClient } from '../axios-client/protocol.js'; +import { DefaultAgentConfigOptions } from './agent-config.js'; import type { AgentConfig, AgentConfigOption } from './protocol.js'; import { AgentConfigFactory } from './protocol.js'; -import { DefaultAgentConfigOptions } from './index.js'; - @singleton() export class AgentConfigManager { @inject(AgentConfigFactory) configFactory: AgentConfigFactory; diff --git a/web/ui/src/modules/agent/agent-config.ts b/web/ui/src/modules/agent/agent-config.ts index 962c444..d1fd4f8 100644 --- a/web/ui/src/modules/agent/agent-config.ts +++ b/web/ui/src/modules/agent/agent-config.ts @@ -1,8 +1,10 @@ import { inject, prop, transient } from '@difizen/mana-app'; -import { AxiosClient } from '../axios-client/index.js'; +import { AxiosClient } from '../axios-client/protocol.js'; +import { ToolManager } from '../tool/tool-manager.js'; +import type { ToolModel } from '../tool/tool-model.js'; -import type { LLMMeta, PlannerMeta, PromptMeta, ToolMeta } from './protocol.js'; +import type { LLMMeta, PlannerMeta, PromptMeta } from './protocol.js'; import { AgentConfigOption } from './protocol.js'; export const DefaultAgentConfigOptions: AgentConfigOption = { @@ -12,6 +14,7 @@ export const DefaultAgentConfigOptions: AgentConfigOption = { @transient() export class AgentConfig { protected axios: AxiosClient; + protected toolManager: ToolManager; isDraft = true; @prop() @@ -23,16 +26,18 @@ export class AgentConfig { planner: PlannerMeta; @prop() - tool: ToolMeta[]; + tool: ToolModel[]; option: AgentConfigOption; constructor( @inject(AgentConfigOption) option: AgentConfigOption, @inject(AxiosClient) axios: AxiosClient, + @inject(ToolManager) toolManager: ToolManager, ) { this.option = option; this.axios = axios; + this.toolManager = toolManager; this.fromMeta(option); } @@ -45,6 +50,6 @@ export class AgentConfig { id: '', nickname: 'string', }; - this.tool = option.tool ?? []; + this.tool = option.tool?.map((item) => this.toolManager.getOrCreate(item)) ?? []; } } diff --git a/web/ui/src/modules/agent/agent-icon.tsx b/web/ui/src/modules/agent/agent-icon.tsx index 1b4ed16..c648754 100644 --- a/web/ui/src/modules/agent/agent-icon.tsx +++ b/web/ui/src/modules/agent/agent-icon.tsx @@ -1,7 +1,8 @@ import type { AvatarProps } from 'antd'; import { Avatar } from 'antd'; -import { toResourceUrl } from '../../common/page-config.js'; +import { toResourceUrl } from '@/common/page-config.js'; + import { MagentLOGO } from '../base-layout/brand/logo.js'; interface IProps extends AvatarProps { diff --git a/web/ui/src/modules/agent/agent-manager.ts b/web/ui/src/modules/agent/agent-manager.ts index b149c95..b96fa3f 100644 --- a/web/ui/src/modules/agent/agent-manager.ts +++ b/web/ui/src/modules/agent/agent-manager.ts @@ -1,6 +1,6 @@ import { inject, singleton } from '@difizen/mana-app'; -import { AxiosClient } from '../axios-client/index.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import { AgentModelFactory } from './protocol.js'; import type { AgentModel, AgentModelOption } from './protocol.js'; @@ -11,7 +11,7 @@ export class AgentManager { @inject(AgentModelFactory) botFactory: AgentModelFactory; @inject(AxiosClient) axios: AxiosClient; - getAgents = async (): Promise => { + getAll = async (): Promise => { const defaultValue: AgentModelOption[] = []; const res = await this.axios.get(`/api/v1/agents`); if (res.status === 200) { @@ -20,7 +20,7 @@ export class AgentManager { return defaultValue; }; - getOrCreateAgent = (option: AgentModelOption): AgentModel => { + getOrCreate = (option: AgentModelOption): AgentModel => { const exist = this.cache.get(option.id); if (exist) { return exist; diff --git a/web/ui/src/modules/agent/agent-market.ts b/web/ui/src/modules/agent/agent-market.ts index 8191050..f8431f8 100644 --- a/web/ui/src/modules/agent/agent-market.ts +++ b/web/ui/src/modules/agent/agent-market.ts @@ -15,8 +15,8 @@ export class AgentMarket { async update() { this.loading = true; - const options = await this.agentManager.getAgents(); - this.list = options.map(this.agentManager.getOrCreateAgent); + const options = await this.agentManager.getAll(); + this.list = options.map(this.agentManager.getOrCreate); this.loading = false; } } diff --git a/web/ui/src/modules/agent/agent-model.ts b/web/ui/src/modules/agent/agent-model.ts index 20215f8..c537555 100644 --- a/web/ui/src/modules/agent/agent-model.ts +++ b/web/ui/src/modules/agent/agent-model.ts @@ -1,15 +1,16 @@ import { inject, prop, transient } from '@difizen/mana-app'; -import { AsyncModel } from '../../common/async-model.js'; -import { AxiosClient } from '../axios-client/index.js'; +import { AsyncModel } from '@/common/async-model.js'; + +import { AxiosClient } from '../axios-client/protocol.js'; import type { KnowledgeModelOption } from '../knowledge/protocol.js'; import { LLMManager } from '../model/llm-manager.js'; import type { LLMModel } from '../model/llm-model.js'; -import type { ToolModelOption } from '../tool/index.js'; -import { ToolManager } from '../tool/index.js'; +import type { ToolModelOption } from '../tool/protocol.js'; +import { ToolManager } from '../tool/tool-manager.js'; import { AgentConfigManager } from './agent-config-manager.js'; -import type { LLMMeta, PromptMeta, PlannerMeta } from './protocol.js'; +import type { PromptMeta, PlannerMeta } from './protocol.js'; import { AgentModelType, AgentModelOption } from './protocol.js'; class Prompt implements PromptMeta { diff --git a/web/ui/src/modules/agent/index.ts b/web/ui/src/modules/agent/index.ts deleted file mode 100644 index 45a1026..0000000 --- a/web/ui/src/modules/agent/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './module.js'; -export * from './agent-manager.js'; -export * from './agent-model.js'; -export * from './agent-config-manager.js'; -export * from './agent-config.js'; -export * from './protocol.js'; diff --git a/web/ui/src/modules/agent/module.ts b/web/ui/src/modules/agent/module.ts index 03395a0..4c2e66a 100644 --- a/web/ui/src/modules/agent/module.ts +++ b/web/ui/src/modules/agent/module.ts @@ -1,7 +1,5 @@ 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'; diff --git a/web/ui/src/modules/app.module.ts b/web/ui/src/modules/app.module.ts index 61bcbeb..38e1ade 100644 --- a/web/ui/src/modules/app.module.ts +++ b/web/ui/src/modules/app.module.ts @@ -1,21 +1,21 @@ import { ManaModule } from '@difizen/mana-app'; -import { AgentConfigViewModule } from '../views/agent-config/index.js'; -import { AgentChatModule } from '../views/agent-dev/index.js'; +import { AgentConfigViewModule } from '../views/agent-config/module.js'; +import { AgentChatModule } from '../views/agent-dev/module.js'; import { AgentFlowModule } from '../views/agent-flow/module.js'; -import { AgentsPageModule } from '../views/agents/index.js'; +import { AgentsPageModule } from '../views/agents/module.js'; import { ChatViewModule } from '../views/chat/module.js'; import { KnowledgePageModule } from '../views/knowledge/module.js'; -import { PortalsModule } from '../views/protal-layout/index.js'; +import { PortalsModule } from '../views/protal-layout/module.js'; import { SessionsViewModule } from '../views/sessions/module.js'; import { ToolPageModule } from '../views/tools/module.js'; import { AgentBotModule } from './agent/module.js'; import { AxiosClientModule } from './axios-client/module.js'; import { BaseLayoutModule } from './base-layout/module.js'; -import { ChatMessageModule } from './chat-message/index.js'; +import { ChatMessageModule } from './chat-message/module.js'; import { ModelModule } from './model/module.js'; -import { SessionModule } from './session/index.js'; +import { SessionModule } from './session/module.js'; import { ToolModule } from './tool/module.js'; export const AppBaseModule = new ManaModule() diff --git a/web/ui/src/modules/axios-client/client.ts b/web/ui/src/modules/axios-client/client.ts index ca1c2b6..76e23cf 100644 --- a/web/ui/src/modules/axios-client/client.ts +++ b/web/ui/src/modules/axios-client/client.ts @@ -4,7 +4,7 @@ import type { Syringe } from '@difizen/mana-app'; import axios from 'axios'; import qs from 'query-string'; -import { getPageConfig } from '../../common/page-config.js'; +import { getPageConfig } from '@/common/page-config.js'; export const getContextClient = (ctx: Syringe.Context) => { const pageConfig = getPageConfig(); diff --git a/web/ui/src/modules/axios-client/index.ts b/web/ui/src/modules/axios-client/index.ts deleted file mode 100644 index e9d8cbd..0000000 --- a/web/ui/src/modules/axios-client/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './module.js'; -export * from './protocol.js'; diff --git a/web/ui/src/modules/base-layout/index.ts b/web/ui/src/modules/base-layout/index.ts deleted file mode 100644 index 28364cf..0000000 --- a/web/ui/src/modules/base-layout/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './layout.js'; diff --git a/web/ui/src/modules/chat-message/ai-message-item.ts b/web/ui/src/modules/chat-message/ai-message-item.ts index 1cba30c..fba99a6 100644 --- a/web/ui/src/modules/chat-message/ai-message-item.ts +++ b/web/ui/src/modules/chat-message/ai-message-item.ts @@ -46,7 +46,7 @@ export class AIChatMessageItem extends ChatMessageItem { }; protected getAgent = async () => { - const agent = await this.agentManager.getOrCreateAgent({ id: this.option.agentId }); + const agent = await this.agentManager.getOrCreate({ id: this.option.agentId }); this.agent = agent; this.agent.fetchInfo(); this.agentDeferred.resolve(agent); diff --git a/web/ui/src/modules/chat-message/chat-message-item.ts b/web/ui/src/modules/chat-message/chat-message-item.ts index cce58e3..7065626 100644 --- a/web/ui/src/modules/chat-message/chat-message-item.ts +++ b/web/ui/src/modules/chat-message/chat-message-item.ts @@ -2,7 +2,7 @@ import { inject, prop, transient } from '@difizen/mana-app'; import type { Dayjs } from 'dayjs'; import dayjs from 'dayjs'; -import { AxiosClient } from '../axios-client/index.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import { ChatMessageItemOption } from './protocol.js'; import type { QuestionState, MessageSender, AnswerState } from './protocol.js'; diff --git a/web/ui/src/modules/chat-message/chat-message-manager.ts b/web/ui/src/modules/chat-message/chat-message-manager.ts index 31272e6..172497e 100644 --- a/web/ui/src/modules/chat-message/chat-message-manager.ts +++ b/web/ui/src/modules/chat-message/chat-message-manager.ts @@ -1,6 +1,6 @@ import { inject, singleton } from '@difizen/mana-app'; -import { AxiosClient } from '../axios-client/index.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import type { ChatMessageModel, ChatMessageOption } from './protocol.js'; import { ChatMessageFactory } from './protocol.js'; diff --git a/web/ui/src/modules/chat-message/chat-message-model.ts b/web/ui/src/modules/chat-message/chat-message-model.ts index cb07450..0cb1ae0 100644 --- a/web/ui/src/modules/chat-message/chat-message-model.ts +++ b/web/ui/src/modules/chat-message/chat-message-model.ts @@ -8,7 +8,7 @@ import type { ParsedEvent } from 'eventsource-parser/stream'; import { AgentManager } from '../agent/agent-manager.js'; import type { AgentModel } from '../agent/agent-model.js'; -import { AxiosClient } from '../axios-client/index.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import { AIChatMessageItem } from './ai-message-item.js'; import type { ChatMessageItem } from './chat-message-item.js'; @@ -99,7 +99,7 @@ export class ChatMessageModel implements Disposable { } protected getAgent = async (id: string) => { - const agent = await this.agentManager.getOrCreateAgent({ id }); + const agent = await this.agentManager.getOrCreate({ id }); this.agent = agent; this.agent.fetchInfo(); this.agentDeferred.resolve(agent); diff --git a/web/ui/src/modules/chat-message/index.ts b/web/ui/src/modules/chat-message/index.ts deleted file mode 100644 index 6fc1001..0000000 --- a/web/ui/src/modules/chat-message/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './module.js'; -export * from './chat-message-manager.js'; diff --git a/web/ui/src/modules/knowledge/index.ts b/web/ui/src/modules/knowledge/index.ts deleted file mode 100644 index 192ae7d..0000000 --- a/web/ui/src/modules/knowledge/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './protocol.js'; -export * from './knowledge-model.js'; -export * from './knowledge-manager.js'; -export * from './module.js'; diff --git a/web/ui/src/modules/knowledge/knowledge-icon.tsx b/web/ui/src/modules/knowledge/knowledge-icon.tsx index f435313..f4a918b 100644 --- a/web/ui/src/modules/knowledge/knowledge-icon.tsx +++ b/web/ui/src/modules/knowledge/knowledge-icon.tsx @@ -2,7 +2,7 @@ import { BookTwoTone } from '@ant-design/icons'; import type { AvatarProps } from 'antd'; import { Avatar } from 'antd'; -import { toResourceUrl } from '../../common/page-config.js'; +import { toResourceUrl } from '@/common/page-config.js'; interface IProps extends AvatarProps { data: { avatar?: string; id?: string }; diff --git a/web/ui/src/modules/knowledge/knowledge-manager.ts b/web/ui/src/modules/knowledge/knowledge-manager.ts index 7424f4f..57b6490 100644 --- a/web/ui/src/modules/knowledge/knowledge-manager.ts +++ b/web/ui/src/modules/knowledge/knowledge-manager.ts @@ -1,6 +1,6 @@ import { inject, prop, singleton } from '@difizen/mana-app'; -import { AxiosClient } from '../axios-client/index.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import { KnowledgeModelFactory, @@ -17,7 +17,7 @@ export class KnowledgeManager { @prop() knowledgeOptions: KnowledgeModelOption[] = []; - getKnowledge = async (): Promise => { + getAll = async (): Promise => { const defaultValue: KnowledgeModelOption[] = []; const res = await this.axios.get(`/api/v1/knowledge`); if (res.status === 200) { @@ -26,7 +26,7 @@ export class KnowledgeManager { return defaultValue; }; - getOrCreateKnowledge = (option: KnowledgeModelOption): KnowledgeModel => { + getOrCreate = (option: KnowledgeModelOption): KnowledgeModel => { const exist = this.cache.get(option.id); if (exist) { return exist; diff --git a/web/ui/src/modules/knowledge/knowledge-model.ts b/web/ui/src/modules/knowledge/knowledge-model.ts index 5261f83..193bef3 100644 --- a/web/ui/src/modules/knowledge/knowledge-model.ts +++ b/web/ui/src/modules/knowledge/knowledge-model.ts @@ -1,7 +1,7 @@ import { inject, prop, transient } from '@difizen/mana-app'; -import { AsyncModel } from '../../common/async-model.js'; -import { AxiosClient } from '../axios-client/index.js'; +import { AsyncModel } from '@/common/async-model.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import { KnowledgeModelOption } from './protocol.js'; import { KnowledgeModelType } from './protocol.js'; diff --git a/web/ui/src/modules/knowledge/knowledge-space.ts b/web/ui/src/modules/knowledge/knowledge-space.ts index 8889fc2..e2bcf6d 100644 --- a/web/ui/src/modules/knowledge/knowledge-space.ts +++ b/web/ui/src/modules/knowledge/knowledge-space.ts @@ -15,8 +15,8 @@ export class KnowledgeSpace { async update() { this.loading = true; - const options = await this.manager.getKnowledge(); - this.list = options.map(this.manager.getOrCreateKnowledge); + const options = await this.manager.getAll(); + this.list = options.map(this.manager.getOrCreate); this.loading = false; } } diff --git a/web/ui/src/modules/session/index.ts b/web/ui/src/modules/session/index.ts deleted file mode 100644 index fcd81e3..0000000 --- a/web/ui/src/modules/session/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './module.js'; -export * from './session-manager.js'; -export * from './protocol.js'; diff --git a/web/ui/src/modules/session/session-manager.ts b/web/ui/src/modules/session/session-manager.ts index 92b2a6b..eccd974 100644 --- a/web/ui/src/modules/session/session-manager.ts +++ b/web/ui/src/modules/session/session-manager.ts @@ -1,7 +1,7 @@ import { inject, singleton } from '@difizen/mana-app'; import qs from 'query-string'; -import { AxiosClient } from '../axios-client/index.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import type { APISession, diff --git a/web/ui/src/modules/session/session-model.ts b/web/ui/src/modules/session/session-model.ts index 274b98d..d6f5248 100644 --- a/web/ui/src/modules/session/session-model.ts +++ b/web/ui/src/modules/session/session-model.ts @@ -5,8 +5,8 @@ import { Emitter } from '@difizen/mana-app'; import { inject, prop, transient } from '@difizen/mana-app'; import dayjs from 'dayjs'; -import { AsyncModel } from '../../common/async-model.js'; -import { AxiosClient } from '../axios-client/index.js'; +import { AsyncModel } from '@/common/async-model.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import type { ChatMessageItem } from '../chat-message/chat-message-item.js'; import { ChatMessageManager } from '../chat-message/chat-message-manager.js'; import type { ChatMessageModel, MessageCreate } from '../chat-message/protocol.js'; diff --git a/web/ui/src/modules/tool/index.ts b/web/ui/src/modules/tool/index.ts deleted file mode 100644 index a196109..0000000 --- a/web/ui/src/modules/tool/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './protocol.js'; -export * from './tool-model.js'; -export * from './tool-manager.js'; -export * from './tool-config.js'; -export * from './tool-config-manager.js'; -export * from './module.js'; diff --git a/web/ui/src/modules/tool/tool-config-manager.ts b/web/ui/src/modules/tool/tool-config-manager.ts index 4880e33..af36bb8 100644 --- a/web/ui/src/modules/tool/tool-config-manager.ts +++ b/web/ui/src/modules/tool/tool-config-manager.ts @@ -1,6 +1,6 @@ import { inject, singleton } from '@difizen/mana-app'; -import { AxiosClient } from '../axios-client/index.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import { ToolConfigFactory, type ToolConfigOption } from './protocol.js'; import type { ToolConfig } from './tool-config.js'; diff --git a/web/ui/src/modules/tool/tool-config.ts b/web/ui/src/modules/tool/tool-config.ts index ab00c60..55fc2bc 100644 --- a/web/ui/src/modules/tool/tool-config.ts +++ b/web/ui/src/modules/tool/tool-config.ts @@ -1,8 +1,8 @@ import { Emitter, inject, prop, transient } from '@difizen/mana-app'; import debounce from 'lodash.debounce'; -import { AsyncModel } from '../../common/async-model.js'; -import { AxiosClient } from '../axios-client/index.js'; +import { AsyncModel } from '@/common/async-model.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import { ToolConfigOption, ToolConfigType } from './protocol.js'; diff --git a/web/ui/src/modules/tool/tool-icon.tsx b/web/ui/src/modules/tool/tool-icon.tsx index aaa6eb8..bc982b9 100644 --- a/web/ui/src/modules/tool/tool-icon.tsx +++ b/web/ui/src/modules/tool/tool-icon.tsx @@ -1,7 +1,7 @@ import type { AvatarProps } from 'antd'; import { Avatar } from 'antd'; -import { toResourceUrl } from '../../common/page-config.js'; +import { toResourceUrl } from '@/common/page-config.js'; interface IProps extends AvatarProps { data: { avatar?: string; id?: string }; diff --git a/web/ui/src/modules/tool/tool-manager.ts b/web/ui/src/modules/tool/tool-manager.ts index 7c157bb..5129748 100644 --- a/web/ui/src/modules/tool/tool-manager.ts +++ b/web/ui/src/modules/tool/tool-manager.ts @@ -1,6 +1,6 @@ import { inject, singleton } from '@difizen/mana-app'; -import { AxiosClient } from '../axios-client/index.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import { ToolFactory, type ToolModel, type ToolModelOption } from './protocol.js'; @@ -10,7 +10,7 @@ export class ToolManager { @inject(ToolFactory) toolFactory: ToolFactory; @inject(AxiosClient) axios: AxiosClient; - getTools = async (): Promise => { + getAll = async (): Promise => { const defaultValue: ToolModelOption[] = []; const res = await this.axios.get(`/api/v1/tools`); if (res.status === 200) { @@ -19,7 +19,7 @@ export class ToolManager { return defaultValue; }; - getOrCreateTool = (option: ToolModelOption): ToolModel => { + getOrCreate = (option: ToolModelOption): ToolModel => { const exist = this.cache.get(option.id); if (exist) { return exist; diff --git a/web/ui/src/modules/tool/tool-model.ts b/web/ui/src/modules/tool/tool-model.ts index 6d75e37..d668636 100644 --- a/web/ui/src/modules/tool/tool-model.ts +++ b/web/ui/src/modules/tool/tool-model.ts @@ -1,7 +1,7 @@ import { Deferred, inject, prop, transient } from '@difizen/mana-app'; -import { AsyncModel } from '../../common/async-model.js'; -import { AxiosClient } from '../axios-client/index.js'; +import { AsyncModel } from '@/common/async-model.js'; +import { AxiosClient } from '../axios-client/protocol.js'; import { ToolModelOption, ToolModelType } from './protocol.js'; import { ToolConfigManager } from './tool-config-manager.js'; diff --git a/web/ui/src/modules/tool/tool-space.ts b/web/ui/src/modules/tool/tool-space.ts index a823c15..43717fa 100644 --- a/web/ui/src/modules/tool/tool-space.ts +++ b/web/ui/src/modules/tool/tool-space.ts @@ -15,8 +15,8 @@ export class ToolSpace { async update() { this.loading = true; - const options = await this.toolManager.getTools(); - this.list = options.map(this.toolManager.getOrCreateTool); + const options = await this.toolManager.getAll(); + this.list = options.map(this.toolManager.getOrCreate); this.loading = false; } } diff --git a/web/ui/src/views/agent-config/components/model-selector/index.tsx b/web/ui/src/views/agent-config/components/model-selector/index.tsx index 0a145d0..6869f86 100644 --- a/web/ui/src/views/agent-config/components/model-selector/index.tsx +++ b/web/ui/src/views/agent-config/components/model-selector/index.tsx @@ -5,11 +5,11 @@ import { Button, Form, Select, Popover, Avatar, Slider } from 'antd'; import type { FC } from 'react'; import { forwardRef, useEffect } from 'react'; +import { LLMManager } from '@/modules/model/llm-manager.js'; import type { LLMModel } from '@/modules/model/llm-model.js'; import { LLMIcon } from '@/modules/model/model-icon/index.js'; +import type { ModelMeta } from '@/modules/model/protocol.js'; -import { LLMManager } from '../../../../modules/model/llm-manager.js'; -import type { ModelMeta } from '../../../../modules/model/protocol.js'; import type { AgentConfigView } from '../../view.js'; import './index.less'; diff --git a/web/ui/src/views/agent-config/knowledge-modal/modal.tsx b/web/ui/src/views/agent-config/knowledge-modal/modal.tsx index 7177355..f741115 100644 --- a/web/ui/src/views/agent-config/knowledge-modal/modal.tsx +++ b/web/ui/src/views/agent-config/knowledge-modal/modal.tsx @@ -5,10 +5,10 @@ import { Modal, Table } from 'antd'; import type { TableRowSelection } from 'antd/es/table/interface.js'; import { useMemo } from 'react'; -import type { AgentModel } from '../../../modules/agent/protocol.js'; -import { KnowledgeIcon } from '../../../modules/knowledge/knowledge-icon.js'; -import { KnowledgeSpace } from '../../../modules/knowledge/knowledge-space.js'; -import type { KnowledgeModelOption } from '../../../modules/knowledge/protocol.js'; +import type { AgentModel } from '@/modules/agent/protocol.js'; +import { KnowledgeIcon } from '@/modules/knowledge/knowledge-icon.js'; +import { KnowledgeSpace } from '@/modules/knowledge/knowledge-space.js'; +import type { KnowledgeModelOption } from '@/modules/knowledge/protocol.js'; import { KnowledgeModalId } from '../protocol.js'; export const KnowledgeModalComponent = ( diff --git a/web/ui/src/views/agent-config/tools-modal/modal.tsx b/web/ui/src/views/agent-config/tools-modal/modal.tsx index 6585dbd..89a6cb5 100644 --- a/web/ui/src/views/agent-config/tools-modal/modal.tsx +++ b/web/ui/src/views/agent-config/tools-modal/modal.tsx @@ -5,10 +5,10 @@ import { Modal, Table } from 'antd'; import type { TableRowSelection } from 'antd/es/table/interface.js'; import { useMemo } from 'react'; -import type { AgentModel } from '../../../modules/agent/protocol.js'; -import type { ToolModelOption } from '../../../modules/tool/protocol.js'; -import { ToolIcon } from '../../../modules/tool/tool-icon.js'; -import { ToolSpace } from '../../../modules/tool/tool-space.js'; +import type { AgentModel } from '@/modules/agent/protocol.js'; +import type { ToolModelOption } from '@/modules/tool/protocol.js'; +import { ToolIcon } from '@/modules/tool/tool-icon.js'; +import { ToolSpace } from '@/modules/tool/tool-space.js'; import { ToolsModalId } from '../protocol.js'; export const ToolsModalComponent = (props: ModalItemProps<{ agent: AgentModel }>) => { diff --git a/web/ui/src/views/agent-config/view.tsx b/web/ui/src/views/agent-config/view.tsx index 35f0e1e..eab0f4f 100644 --- a/web/ui/src/views/agent-config/view.tsx +++ b/web/ui/src/views/agent-config/view.tsx @@ -13,10 +13,10 @@ import { import { Flex } from 'antd'; import { forwardRef } from 'react'; -import { AgentManager } from '../../modules/agent/index.js'; -import type { AgentModel } from '../../modules/agent/index.js'; -import { KnowledgeIcon } from '../../modules/knowledge/knowledge-icon.js'; -import { ToolIcon } from '../../modules/tool/tool-icon.js'; +import { AgentManager } from '@/modules/agent/agent-manager.js'; +import type { AgentModel } from '@/modules/agent/protocol.js'; +import { KnowledgeIcon } from '@/modules/knowledge/knowledge-icon.js'; +import { ToolIcon } from '@/modules/tool/tool-icon.js'; import { CharacterSetting } from './components/character-setting/index.js'; import { ConfigList } from './components/config-selector/index.js'; @@ -131,7 +131,7 @@ export class AgentConfigView extends BaseView { get modelOptions() { // TODO 大模型optios列表和对应存取值要怎么取? return ( - this.agent?.llm?.model_name?.map((item) => { + this.agent?.llm?.models?.map((item) => { return { label: item, value: item, @@ -142,7 +142,7 @@ export class AgentConfigView extends BaseView { protected initAgent = (agentId = this.agentId) => { if (agentId) { - const agent = this.agentManager.getOrCreateAgent({ id: agentId }); + const agent = this.agentManager.getOrCreate({ id: agentId }); agent.fetchInfo(); this.agent = agent; return agent; diff --git a/web/ui/src/views/agent-dev/chat-view.tsx b/web/ui/src/views/agent-dev/chat-view.tsx index db75bc7..fdfc7b1 100644 --- a/web/ui/src/views/agent-dev/chat-view.tsx +++ b/web/ui/src/views/agent-dev/chat-view.tsx @@ -13,10 +13,10 @@ import { forwardRef, useEffect } from 'react'; import { useMatch } from 'react-router-dom'; import { history } from 'umi'; -import { AgentManager } from '../../modules/agent/agent-manager.js'; -import type { AgentModel } from '../../modules/agent/protocol.js'; -import { PageView } from '../../modules/base-layout/page-view.js'; -import type { SessionModel } from '../../modules/session/protocol.js'; +import { AgentManager } from '@/modules/agent/agent-manager.js'; +import type { AgentModel } from '@/modules/agent/protocol.js'; +import { PageView } from '@/modules/base-layout/page-view.js'; +import type { SessionModel } from '@/modules/session/protocol.js'; import { ChatView } from '../chat/view.js'; import { SessionsView } from '../sessions/view.js'; @@ -119,7 +119,7 @@ export class AgentView extends PageView { }; protected initAgent = () => { if (this.agentId) { - const agent = this.agentManager.getOrCreateAgent({ id: this.agentId }); + const agent = this.agentManager.getOrCreate({ id: this.agentId }); agent.fetchInfo(); this.agent = agent; return agent; diff --git a/web/ui/src/views/agent-dev/debug-modal.tsx b/web/ui/src/views/agent-dev/debug-modal.tsx index d1a3066..42cb452 100644 --- a/web/ui/src/views/agent-dev/debug-modal.tsx +++ b/web/ui/src/views/agent-dev/debug-modal.tsx @@ -8,8 +8,8 @@ import { Col, Drawer, Row, Select, Tree } from 'antd'; import { useState } from 'react'; import { DefaultLLMIcon } from '@/modules/model/model-icon/index.js'; +import { DefaultToolIcon } from '@/modules/tool/tool-icon.js'; -import { DefaultToolIcon } from '../../modules/tool/tool-icon.js'; import { HumanIcon } from '../chat/components/message/human-message.js'; import type { ChatView } from '../chat/view.js'; diff --git a/web/ui/src/views/agent-dev/dev-view.tsx b/web/ui/src/views/agent-dev/dev-view.tsx index eea260b..56c569f 100644 --- a/web/ui/src/views/agent-dev/dev-view.tsx +++ b/web/ui/src/views/agent-dev/dev-view.tsx @@ -5,7 +5,7 @@ import { Button } from 'antd'; import { forwardRef, useEffect } from 'react'; import { useMatch } from 'react-router-dom'; -import type { AgentConfigManager } from '../../modules/agent/agent-config-manager.js'; +import type { AgentConfigManager } from '@/modules/agent/agent-config-manager.js'; import { AgentConfigView } from '../agent-config/view.js'; import { AgentView } from './chat-view.js'; diff --git a/web/ui/src/views/agent-flow/agent-flow-view.tsx b/web/ui/src/views/agent-flow/agent-flow-view.tsx index d0f82f6..ea735c3 100644 --- a/web/ui/src/views/agent-flow/agent-flow-view.tsx +++ b/web/ui/src/views/agent-flow/agent-flow-view.tsx @@ -1,20 +1,9 @@ -import { SaveOutlined } from '@ant-design/icons'; import { FlowWithPanel } from '@difizen/magent-flow'; -import { - BaseView, - ViewInstance, - inject, - prop, - useInject, - view, - ViewOption, - transient, -} from '@difizen/mana-app'; -import { Flex } from 'antd'; +import { BaseView, inject, prop, view, ViewOption, transient } from '@difizen/mana-app'; import { forwardRef } from 'react'; -import { AgentManager } from '../../modules/agent/index.js'; -import type { AgentModel } from '../../modules/agent/index.js'; +import { AgentManager } from '@/modules/agent/agent-manager.js'; +import type { AgentModel } from '@/modules/agent/protocol.js'; import './index.less'; @@ -22,8 +11,6 @@ const viewId = 'magent-agent-flow'; const AgentFlowComponent = forwardRef( function AgentConfigViewComponent(props, ref) { - const instance = useInject(ViewInstance); - return (
@@ -56,7 +43,7 @@ export class AgentFlowView extends BaseView { get modelOptions() { // TODO 大模型optios列表和对应存取值要怎么取? return ( - this.agent?.llm?.model_name?.map((item) => { + this.agent?.llm?.models?.map((item) => { return { label: item, value: item, @@ -67,7 +54,7 @@ export class AgentFlowView extends BaseView { protected initAgent = (agentId = this.agentId) => { if (agentId) { - const agent = this.agentManager.getOrCreateAgent({ id: agentId }); + const agent = this.agentManager.getOrCreate({ id: agentId }); agent.fetchInfo(); this.agent = agent; return agent; diff --git a/web/ui/src/views/agent-flow/flow-dev-view.tsx b/web/ui/src/views/agent-flow/flow-dev-view.tsx index a892ac4..1c78e92 100644 --- a/web/ui/src/views/agent-flow/flow-dev-view.tsx +++ b/web/ui/src/views/agent-flow/flow-dev-view.tsx @@ -4,7 +4,7 @@ import { BoxPanel } from '@difizen/mana-react'; import { forwardRef, useEffect } from 'react'; import { useMatch } from 'react-router-dom'; -import type { AgentConfigManager } from '../../modules/agent/agent-config-manager.js'; +import type { AgentConfigManager } from '@/modules/agent/agent-config-manager.js'; import { AgentView } from '../agent-dev/chat-view.js'; import { AgentFlowView } from './agent-flow-view.js'; diff --git a/web/ui/src/views/agents/modal/create.tsx b/web/ui/src/views/agents/modal/create.tsx index 5a2ab05..f287d60 100644 --- a/web/ui/src/views/agents/modal/create.tsx +++ b/web/ui/src/views/agents/modal/create.tsx @@ -7,8 +7,8 @@ import { Modal } from 'antd'; import type { PropsWithChildren } from 'react'; import { useEffect, useState } from 'react'; -import { AvatarUpload } from '../../../components/avatar-upload/index.js'; -import { AgentIcon } from '../../../modules/agent/agent-icon.js'; +import { AvatarUpload } from '@/components/avatar-upload/index.js'; +import { AgentIcon } from '@/modules/agent/agent-icon.js'; import './index.less'; diff --git a/web/ui/src/views/agents/view.tsx b/web/ui/src/views/agents/view.tsx index e79ce0a..29f6758 100644 --- a/web/ui/src/views/agents/view.tsx +++ b/web/ui/src/views/agents/view.tsx @@ -14,8 +14,8 @@ import { forwardRef } from 'react'; import { history } from 'umi'; import './index.less'; -import { AgentIcon } from '../../modules/agent/agent-icon.js'; -import { AgentMarket } from '../../modules/agent/agent-market.js'; +import { AgentIcon } from '@/modules/agent/agent-icon.js'; +import { AgentMarket } from '@/modules/agent/agent-market.js'; import { AgentCreateModal } from './modal/create.js'; diff --git a/web/ui/src/views/chat/components/message/ai-message.tsx b/web/ui/src/views/chat/components/message/ai-message.tsx index 6a64f2d..6052263 100644 --- a/web/ui/src/views/chat/components/message/ai-message.tsx +++ b/web/ui/src/views/chat/components/message/ai-message.tsx @@ -9,10 +9,11 @@ import classNames from 'classnames'; import copy from 'copy-to-clipboard'; import type { ReactNode } from 'react'; -import { AgentIcon } from '../../../../modules/agent/agent-icon.js'; -import type { AIChatMessageItem } from '../../../../modules/chat-message/ai-message-item.js'; -import type { ChatMessageModel } from '../../../../modules/chat-message/chat-message-model.js'; -import { AnswerState } from '../../../../modules/chat-message/protocol.js'; +import { AgentIcon } from '@/modules/agent/agent-icon.js'; +import type { AIChatMessageItem } from '@/modules/chat-message/ai-message-item.js'; +import type { ChatMessageModel } from '@/modules/chat-message/chat-message-model.js'; +import { AnswerState } from '@/modules/chat-message/protocol.js'; + import type { ChatView } from '../../view.js'; import { Markdown } from './markdown/index.js'; diff --git a/web/ui/src/views/chat/components/message/exchange.tsx b/web/ui/src/views/chat/components/message/exchange.tsx index 594fa6f..1f739fc 100644 --- a/web/ui/src/views/chat/components/message/exchange.tsx +++ b/web/ui/src/views/chat/components/message/exchange.tsx @@ -1,4 +1,4 @@ -import type { ChatMessageModel } from '../../../../modules/chat-message/chat-message-model.js'; +import type { ChatMessageModel } from '@/modules/chat-message/chat-message-model.js'; import { Message } from './message.js'; diff --git a/web/ui/src/views/chat/components/message/human-message.tsx b/web/ui/src/views/chat/components/message/human-message.tsx index c50ba96..9112d6f 100644 --- a/web/ui/src/views/chat/components/message/human-message.tsx +++ b/web/ui/src/views/chat/components/message/human-message.tsx @@ -4,8 +4,9 @@ import { Avatar, Space } from 'antd'; import classNames from 'classnames'; import type { ReactNode } from 'react'; -import type { HumanChatMessageItem } from '../../../../modules/chat-message/chat-message-item.js'; -import type { ChatMessageModel } from '../../../../modules/chat-message/chat-message-model.js'; +import type { HumanChatMessageItem } from '@/modules/chat-message/chat-message-item.js'; +import type { ChatMessageModel } from '@/modules/chat-message/chat-message-model.js'; + import type { ChatView } from '../../view.js'; import { TextMessage } from './text/index.js'; diff --git a/web/ui/src/views/chat/components/message/message.tsx b/web/ui/src/views/chat/components/message/message.tsx index 018cdd0..a87fe77 100644 --- a/web/ui/src/views/chat/components/message/message.tsx +++ b/web/ui/src/views/chat/components/message/message.tsx @@ -1,10 +1,10 @@ import { useObserve } from '@difizen/mana-app'; -import { AIChatMessageItem } from '../../../../modules/chat-message/ai-message-item.js'; -import type { ChatMessageItem } from '../../../../modules/chat-message/chat-message-item.js'; -import { HumanChatMessageItem } from '../../../../modules/chat-message/chat-message-item.js'; -import type { ChatMessageModel } from '../../../../modules/chat-message/chat-message-model.js'; -import { PeerChatMessageItem } from '../../../../modules/chat-message/peer-message-item-model.js'; +import { AIChatMessageItem } from '@/modules/chat-message/ai-message-item.js'; +import type { ChatMessageItem } from '@/modules/chat-message/chat-message-item.js'; +import { HumanChatMessageItem } from '@/modules/chat-message/chat-message-item.js'; +import type { ChatMessageModel } from '@/modules/chat-message/chat-message-model.js'; +import { PeerChatMessageItem } from '@/modules/chat-message/peer-message-item-model.js'; import { AIMessage } from './ai-message.js'; import { HumanMessage } from './human-message.js'; diff --git a/web/ui/src/views/chat/components/message/peer-message.tsx b/web/ui/src/views/chat/components/message/peer-message.tsx index 0579a20..6911553 100644 --- a/web/ui/src/views/chat/components/message/peer-message.tsx +++ b/web/ui/src/views/chat/components/message/peer-message.tsx @@ -10,11 +10,12 @@ import classNames from 'classnames'; import copy from 'copy-to-clipboard'; import type { ReactNode } from 'react'; -import { AgentIcon } from '../../../../modules/agent/agent-icon.js'; -import type { ChatMessageModel } from '../../../../modules/chat-message/chat-message-model.js'; -import type { PeerChatMessageItem } from '../../../../modules/chat-message/peer-message-item-model.js'; -import type { ChatEventStepQA } from '../../../../modules/chat-message/protocol.js'; -import { AnswerState } from '../../../../modules/chat-message/protocol.js'; +import { AgentIcon } from '@/modules/agent/agent-icon.js'; +import type { ChatMessageModel } from '@/modules/chat-message/chat-message-model.js'; +import type { PeerChatMessageItem } from '@/modules/chat-message/peer-message-item-model.js'; +import type { ChatEventStepQA } from '@/modules/chat-message/protocol.js'; +import { AnswerState } from '@/modules/chat-message/protocol.js'; + import type { ChatView } from '../../view.js'; import { Markdown } from './markdown/index.js'; diff --git a/web/ui/src/views/chat/view.tsx b/web/ui/src/views/chat/view.tsx index fdbbf95..7f2df96 100644 --- a/web/ui/src/views/chat/view.tsx +++ b/web/ui/src/views/chat/view.tsx @@ -11,21 +11,20 @@ import { ViewOption, } from '@difizen/mana-app'; import { useInject } from '@difizen/mana-app'; -import { Avatar, FloatButton } from 'antd'; +import { FloatButton } from 'antd'; import classnames from 'classnames'; import classNames from 'classnames'; import type { RefObject } from 'react'; import { useEffect, useRef } from 'react'; -import { AgentIcon } from '../../modules/agent/agent-icon.js'; -import { AgentManager } from '../../modules/agent/agent-manager.js'; -import type { AgentModel } from '../../modules/agent/protocol.js'; -import { AxiosClient } from '../../modules/axios-client/index.js'; -import { MagentLOGO } from '../../modules/base-layout/brand/logo.js'; -import { ChatMessageManager } from '../../modules/chat-message/chat-message-manager.js'; -import type { MessageCreate } from '../../modules/chat-message/protocol.js'; -import { SessionManager } from '../../modules/session/session-manager.js'; -import type { SessionModel } from '../../modules/session/session-model.js'; +import { AgentIcon } from '@/modules/agent/agent-icon.js'; +import { AgentManager } from '@/modules/agent/agent-manager.js'; +import type { AgentModel } from '@/modules/agent/protocol.js'; +import { AxiosClient } from '@/modules/axios-client/protocol.js'; +import { ChatMessageManager } from '@/modules/chat-message/chat-message-manager.js'; +import type { MessageCreate } from '@/modules/chat-message/protocol.js'; +import { SessionManager } from '@/modules/session/session-manager.js'; +import type { SessionModel } from '@/modules/session/session-model.js'; import { Input } from './components/input/index.js'; import { MessageExchange } from './components/message/exchange.js'; @@ -174,7 +173,7 @@ export class ChatView extends BaseView { } protected getAgent = async (id: string) => { - this.agent = await this.agentManager.getOrCreateAgent({ id }); + this.agent = await this.agentManager.getOrCreate({ id }); this.agent.fetchInfo(); this.agentDeferred.resolve(this.agent); }; diff --git a/web/ui/src/views/knowledge/module.ts b/web/ui/src/views/knowledge/module.ts index 0dc638b..b21e340 100644 --- a/web/ui/src/views/knowledge/module.ts +++ b/web/ui/src/views/knowledge/module.ts @@ -1,6 +1,6 @@ import { createViewPreference, ManaModule } from '@difizen/mana-app'; -import { KnowledgeModule } from '../../modules/knowledge/module.js'; +import { KnowledgeModule } from '@/modules/knowledge/module.js'; import { KnowledgeView, slot } from './view.js'; diff --git a/web/ui/src/views/knowledge/view.tsx b/web/ui/src/views/knowledge/view.tsx index 95c57b2..6eb4586 100644 --- a/web/ui/src/views/knowledge/view.tsx +++ b/web/ui/src/views/knowledge/view.tsx @@ -11,12 +11,12 @@ import { import { Col, List, Row } from 'antd'; import { forwardRef, useState } from 'react'; -import { KnowledgeIcon } from '../../modules/knowledge/knowledge-icon.js'; -import { KnowledgeManager } from '../../modules/knowledge/knowledge-manager.js'; +import { KnowledgeIcon } from '@/modules/knowledge/knowledge-icon.js'; +import { KnowledgeManager } from '@/modules/knowledge/knowledge-manager.js'; import type { KnowledgeModel, KnowledgeModelOption, -} from '../../modules/knowledge/protocol.js'; +} from '@/modules/knowledge/protocol.js'; import './index.less'; @@ -91,8 +91,8 @@ export class KnowledgeView extends BaseView { loadig = false; async update() { - const options = await this.manager.getKnowledge(); - this.list = options.map(this.manager.getOrCreateKnowledge); + const options = await this.manager.getAll(); + this.list = options.map(this.manager.getOrCreate); } override async onViewMount(): Promise { diff --git a/web/ui/src/views/sessions/conversation-list/index.tsx b/web/ui/src/views/sessions/conversation-list/index.tsx index 69665bc..016b1d1 100644 --- a/web/ui/src/views/sessions/conversation-list/index.tsx +++ b/web/ui/src/views/sessions/conversation-list/index.tsx @@ -1,11 +1,12 @@ -import { CaretRightOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons'; +import { CaretRightOutlined, DeleteOutlined } from '@ant-design/icons'; import { useInject, ViewInstance } from '@difizen/mana-app'; import { Input, Popconfirm } from 'antd'; import type { TextAreaRef } from 'antd/es/input/TextArea.js'; import classNames from 'classnames'; import { useLayoutEffect, useRef, useState } from 'react'; -import type { SessionModel } from '../../../modules/session/index.js'; +import type { SessionModel } from '@/modules/session/session-model.js'; + import type { SessionsView } from '../view.js'; import './index.less'; diff --git a/web/ui/src/views/sessions/view.tsx b/web/ui/src/views/sessions/view.tsx index ee240b2..216c229 100644 --- a/web/ui/src/views/sessions/view.tsx +++ b/web/ui/src/views/sessions/view.tsx @@ -14,12 +14,13 @@ import { Button } from 'antd'; import classNames from 'classnames'; import { forwardRef, useMemo } from 'react'; -import type { SessionModel } from '../../modules/session/index.js'; -import { SessionManager } from '../../modules/session/index.js'; +import { SessionManager } from '@/modules/session/session-manager.js'; +import type { SessionModel } from '@/modules/session/session-model.js'; -import './index.less'; import { ConversationItem } from './conversation-list/index.js'; +import './index.less'; + const viewId = 'magent-sessions'; function isYesterday(inputDateStr: string) { diff --git a/web/ui/src/views/tools/module.ts b/web/ui/src/views/tools/module.ts index 9066963..952c665 100644 --- a/web/ui/src/views/tools/module.ts +++ b/web/ui/src/views/tools/module.ts @@ -1,6 +1,6 @@ import { createViewPreference, ManaModule } from '@difizen/mana-app'; -import { ToolSpace } from '../../modules/tool/tool-space.js'; +import { ToolSpace } from '@/modules/tool/tool-space.js'; import { ToolsView, slot } from './view.js'; diff --git a/web/ui/src/views/tools/view.tsx b/web/ui/src/views/tools/view.tsx index 0799dbf..17a06ad 100644 --- a/web/ui/src/views/tools/view.tsx +++ b/web/ui/src/views/tools/view.tsx @@ -12,8 +12,8 @@ import { Col, List, Row, Tag, Tooltip } from 'antd'; import { forwardRef, useEffect, useRef, useState } from 'react'; import './index.less'; -import { ToolIcon } from '../../modules/tool/tool-icon.js'; -import { ToolSpace } from '../../modules/tool/tool-space.js'; +import { ToolIcon } from '@/modules/tool/tool-icon.js'; +import { ToolSpace } from '@/modules/tool/tool-space.js'; export interface ToolItem { nickname: string; From f750528dd6c30b3aaf43fcb2c166db0560b734c8 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 27 Aug 2024 22:09:20 +0800 Subject: [PATCH 08/78] feat(ui): optmize flow dag style --- .../src/{views/agent-dev => common}/utils.ts | 0 web/ui/src/modules/app.module.ts | 20 ++++---- web/ui/src/views/agent-dev/dev-view.tsx | 5 +- web/ui/src/views/agent-dev/module.ts | 2 - web/ui/src/views/agent-flow/flow-dev-view.tsx | 47 ++++++++++++++--- web/ui/src/views/agent-flow/index.less | 50 +++++++++++++++---- .../debug-drawer-contribution.ts | 4 +- .../debug-drawer.tsx} | 16 +++--- web/ui/src/views/debug/module.ts | 9 ++++ web/ui/src/views/debug/protocol.ts | 1 + 10 files changed, 114 insertions(+), 40 deletions(-) rename web/ui/src/{views/agent-dev => common}/utils.ts (100%) rename web/ui/src/views/{agent-dev => debug}/debug-drawer-contribution.ts (73%) rename web/ui/src/views/{agent-dev/debug-modal.tsx => debug/debug-drawer.tsx} (92%) create mode 100644 web/ui/src/views/debug/module.ts create mode 100644 web/ui/src/views/debug/protocol.ts diff --git a/web/ui/src/views/agent-dev/utils.ts b/web/ui/src/common/utils.ts similarity index 100% rename from web/ui/src/views/agent-dev/utils.ts rename to web/ui/src/common/utils.ts diff --git a/web/ui/src/modules/app.module.ts b/web/ui/src/modules/app.module.ts index 38e1ade..c3dcfee 100644 --- a/web/ui/src/modules/app.module.ts +++ b/web/ui/src/modules/app.module.ts @@ -1,14 +1,15 @@ import { ManaModule } from '@difizen/mana-app'; -import { AgentConfigViewModule } from '../views/agent-config/module.js'; -import { AgentChatModule } from '../views/agent-dev/module.js'; -import { AgentFlowModule } from '../views/agent-flow/module.js'; -import { AgentsPageModule } from '../views/agents/module.js'; -import { ChatViewModule } from '../views/chat/module.js'; -import { KnowledgePageModule } from '../views/knowledge/module.js'; -import { PortalsModule } from '../views/protal-layout/module.js'; -import { SessionsViewModule } from '../views/sessions/module.js'; -import { ToolPageModule } from '../views/tools/module.js'; +import { AgentConfigViewModule } from '@/views/agent-config/module.js'; +import { AgentChatModule } from '@/views/agent-dev/module.js'; +import { AgentFlowModule } from '@/views/agent-flow/module.js'; +import { AgentsPageModule } from '@/views/agents/module.js'; +import { ChatViewModule } from '@/views/chat/module.js'; +import { DebugModule } from '@/views/debug/module.js'; +import { KnowledgePageModule } from '@/views/knowledge/module.js'; +import { PortalsModule } from '@/views/protal-layout/module.js'; +import { SessionsViewModule } from '@/views/sessions/module.js'; +import { ToolPageModule } from '@/views/tools/module.js'; import { AgentBotModule } from './agent/module.js'; import { AxiosClientModule } from './axios-client/module.js'; @@ -41,6 +42,7 @@ export const AppBaseModule = new ManaModule() AgentConfigViewModule, PortalsModule, AgentFlowModule, + DebugModule, ); export default AppBaseModule; diff --git a/web/ui/src/views/agent-dev/dev-view.tsx b/web/ui/src/views/agent-dev/dev-view.tsx index 56c569f..675184b 100644 --- a/web/ui/src/views/agent-dev/dev-view.tsx +++ b/web/ui/src/views/agent-dev/dev-view.tsx @@ -6,10 +6,11 @@ import { forwardRef, useEffect } from 'react'; import { useMatch } from 'react-router-dom'; import type { AgentConfigManager } from '@/modules/agent/agent-config-manager.js'; + import { AgentConfigView } from '../agent-config/view.js'; +import { DebugDrawer } from '../debug/debug-drawer.js'; import { AgentView } from './chat-view.js'; -import { DebugModal } from './debug-modal.js'; import './index.less'; const viewId = 'magent-agent-dev'; @@ -38,7 +39,7 @@ const AgentDevComponent = forwardRef(

预览

+

预览

+
+
{instance.chat && }
- */} + + {instance.hideChat && ( + + )} ); @@ -49,6 +81,9 @@ const AgentFlowDevComponent = forwardRef( @singleton() @view(viewId) export class AgentFlowDevView extends AgentView { + @prop() + hideChat = false; + protected agentConfigManager: AgentConfigManager; agentFlow?: AgentFlowView; diff --git a/web/ui/src/views/agent-flow/index.less b/web/ui/src/views/agent-flow/index.less index e7c505e..5b11ca3 100644 --- a/web/ui/src/views/agent-flow/index.less +++ b/web/ui/src/views/agent-flow/index.less @@ -19,36 +19,59 @@ .magent-agent-flow-dev-layout { height: 100%; width: 100%; -} - -.magent-agent-dev-layout { - height: 100%; &-container { - gap: 16px; box-sizing: border-box; - padding: 12px 24px; + } + + &-chat-switch { + position: absolute; + right: 0; + top: 16px; + z-index: 1; } &-config { width: 55%; + + .magent-agent-flow { + > :first-child { + > :first-child { + box-shadow: var(--mana-ant-box-shadow-card); + z-index: 1; + } + } + + .react-flow { + background-color: var(--mana-ant-color-bg-layout); + } + } } &-chat-dev { height: 100%; - min-width: 520px; - width: 520px; + min-width: 416px; + width: 416px; background-color: var(--mana-color-bg-container); - border-radius: 8px; + box-shadow: var(--mana-ant-box-shadow-card); &-header { - padding: 0 24px; + padding: 0 24px 0 6px; height: 64px; border-bottom: 1px solid var(--mana-color-border); display: flex; align-items: center; justify-content: space-between; + &-left { + display: flex; + align-items: center; + + button { + margin-right: 16px; + } + } + h3 { margin: 0; } @@ -58,6 +81,12 @@ height: calc(100% - 64px); } } + + &-chat-dev-hide { + width: 0; + min-width: 0; + transition: var(--mana-ant-motion-duration-fast); + } } .magent-debug { @@ -127,5 +156,4 @@ flex-direction: column; background-color: var(--mana-color-bg-container); box-sizing: border-box; - border-radius: 8px; } diff --git a/web/ui/src/views/agent-dev/debug-drawer-contribution.ts b/web/ui/src/views/debug/debug-drawer-contribution.ts similarity index 73% rename from web/ui/src/views/agent-dev/debug-drawer-contribution.ts rename to web/ui/src/views/debug/debug-drawer-contribution.ts index 60e2843..681fb15 100644 --- a/web/ui/src/views/agent-dev/debug-drawer-contribution.ts +++ b/web/ui/src/views/debug/debug-drawer-contribution.ts @@ -1,10 +1,10 @@ import { ModalContribution, singleton } from '@difizen/mana-app'; -import { DebugModal } from './debug-modal.js'; +import { DebugDrawer } from './debug-drawer.js'; @singleton({ contrib: [ModalContribution] }) export class DebugDrawerContribution implements ModalContribution { registerModal() { - return DebugModal; + return DebugDrawer; } } diff --git a/web/ui/src/views/agent-dev/debug-modal.tsx b/web/ui/src/views/debug/debug-drawer.tsx similarity index 92% rename from web/ui/src/views/agent-dev/debug-modal.tsx rename to web/ui/src/views/debug/debug-drawer.tsx index 42cb452..430f88a 100644 --- a/web/ui/src/views/agent-dev/debug-modal.tsx +++ b/web/ui/src/views/debug/debug-drawer.tsx @@ -7,29 +7,29 @@ import { Avatar } from 'antd'; import { Col, Drawer, Row, Select, Tree } from 'antd'; import { useState } from 'react'; +import { copy2clipboard } from '@/common/utils.js'; import { DefaultLLMIcon } from '@/modules/model/model-icon/index.js'; import { DefaultToolIcon } from '@/modules/tool/tool-icon.js'; import { HumanIcon } from '../chat/components/message/human-message.js'; import type { ChatView } from '../chat/view.js'; -import { copy2clipboard } from './utils.js'; +import { debugDrawerId } from './protocol.js'; -export function DebugModalComponentContext(props: ModalItemProps<{ chat: ChatView }>) { +export function DebugDrawerComponentContext(props: ModalItemProps<{ chat: ChatView }>) { const { data } = props; if (!data) { return null; } return ( - + ); } -export function DebugModalComponent({ +export function DebugDrawerComponent({ visible, close, - data, }: ModalItemProps<{ chat: ChatView }>) { const chat = useInject(ViewInstance); const [selected, setSelected] = useState(undefined); @@ -137,7 +137,7 @@ export function DebugModalComponent({ ); } -export const DebugModal: ModalItem = { - id: 'debug.modal', - component: DebugModalComponentContext, +export const DebugDrawer: ModalItem = { + id: debugDrawerId, + component: DebugDrawerComponentContext, }; diff --git a/web/ui/src/views/debug/module.ts b/web/ui/src/views/debug/module.ts new file mode 100644 index 0000000..72a10c3 --- /dev/null +++ b/web/ui/src/views/debug/module.ts @@ -0,0 +1,9 @@ +import { ManaModule } from '@difizen/mana-app'; + +import { AgentConfigViewModule } from '../agent-config/module.js'; + +import { DebugDrawerContribution } from './debug-drawer-contribution.js'; + +export const DebugModule = ManaModule.create() + .register(DebugDrawerContribution) + .dependOn(AgentConfigViewModule); diff --git a/web/ui/src/views/debug/protocol.ts b/web/ui/src/views/debug/protocol.ts new file mode 100644 index 0000000..6d1395e --- /dev/null +++ b/web/ui/src/views/debug/protocol.ts @@ -0,0 +1 @@ +export const debugDrawerId = 'debug.drawer'; From fd81dffce73bd799ccd09812ce428ec3a363079f Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 27 Aug 2024 22:14:49 +0800 Subject: [PATCH 09/78] feat(ui): modify the font smoothing strategy to be more eye-friendly --- web/ui/src/modules/base-layout/index.less | 1 + 1 file changed, 1 insertion(+) diff --git a/web/ui/src/modules/base-layout/index.less b/web/ui/src/modules/base-layout/index.less index b13c097..cbc517c 100644 --- a/web/ui/src/modules/base-layout/index.less +++ b/web/ui/src/modules/base-layout/index.less @@ -6,6 +6,7 @@ body { height: 100vh; box-sizing: border-box; background-color: rgb(244, 244, 246); + -webkit-font-smoothing: antialiased; .mana-header { background: #fff; From 70ab78009f6ec8a33b7221ccfe38a2fe6d8f075e Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Wed, 28 Aug 2024 01:54:38 +0800 Subject: [PATCH 10/78] refactor: reorganize the project front-end directory --- .prettierignore | 1 + pnpm-workspace.yaml | 5 +- {web => web-apps}/platform/.editorconfig | 0 {web => web-apps}/platform/.eslintignore | 0 {web => web-apps}/platform/.eslintrc.json | 0 {web => web-apps}/platform/.eslintrc.mjs | 0 {web => web-apps}/platform/.gitignore | 0 {web => web-apps}/platform/.prettierignore | 0 {web => web-apps}/platform/.prettierrc.json | 0 {web => web-apps}/platform/.stylelintignore | 0 {web => web-apps}/platform/.stylelintrc | 0 {web => web-apps}/platform/.umirc.ts | 0 {web => web-apps}/platform/README.md | 0 .../platform/dumi-plugin-nodenext.ts | 0 {web => web-apps}/platform/package.json | 0 {web => web-apps}/platform/public/favicon.ico | Bin {web => web-apps}/platform/routes.ts | 0 {web => web-apps}/platform/src/app.ts | 0 .../platform/src/common/async-model.ts | 0 .../platform/src/constant/default.ts | 0 .../modules/agent-bot/agent-bot-manager.ts | 0 .../src/modules/agent-bot/agent-bot.ts | 0 .../modules/agent-bot/agent-config-manager.ts | 0 .../src/modules/agent-bot/agent-config.ts | 0 .../platform/src/modules/agent-bot/index.ts | 0 .../platform/src/modules/agent-bot/module.ts | 0 .../src/modules/agent-bot/protocol.ts | 0 .../platform/src/modules/agent-module.ts | 0 .../platform/src/modules/app.module.ts | 0 .../src/modules/axios-client/client.ts | 0 .../src/modules/axios-client/index.ts | 0 .../src/modules/axios-client/module.ts | 0 .../src/modules/axios-client/protocol.ts | 0 .../platform/src/modules/chat/chat-message.ts | 0 .../platform/src/modules/chat/chat-turn.ts | 0 .../platform/src/modules/chat/chat.ts | 0 .../src/modules/chat/components/chat.tsx | 0 .../src/modules/chat/components/index.less | 0 .../modules/chat/components/input/icon.tsx | 0 .../modules/chat/components/input/index.less | 0 .../modules/chat/components/input/index.tsx | 0 .../modules/chat/components/message/group.tsx | 0 .../chat/components/message/index.less | 0 .../message/markdown-message/index.less | 0 .../message/markdown-message/index.tsx | 0 .../components/message/markdown/index.less | 0 .../components/message/markdown/index.tsx | 0 .../markdown/modules/CodeBlock/index.less | 0 .../markdown/modules/CodeBlock/index.tsx | 0 .../chat/components/message/message.tsx | 0 .../chat/components/message/text/index.less | 0 .../chat/components/message/text/index.tsx | 0 .../modules/chat/components/typing/index.less | 0 .../modules/chat/components/typing/index.tsx | 0 .../platform/src/modules/chat/index.ts | 0 .../platform/src/modules/chat/manager.ts | 0 .../src/modules/chat/message-manager.ts | 0 .../platform/src/modules/chat/module.ts | 0 .../platform/src/modules/chat/protocol.ts | 0 .../src/modules/model/built-in-model-meta.ts | 0 .../platform/src/modules/model/index.ts | 0 .../src/modules/model/model-manager.ts | 0 .../platform/src/modules/model/model.ts | 0 .../platform/src/modules/model/module.ts | 0 .../platform/src/modules/model/protocol.ts | 0 .../platform/src/modules/plugin/index.ts | 0 .../platform/src/modules/plugin/module.ts | 0 .../modules/plugin/plugin-config-manager.ts | 0 .../src/modules/plugin/plugin-config.ts | 0 .../src/modules/plugin/plugin-manager.ts | 0 .../platform/src/modules/plugin/plugin.ts | 0 .../platform/src/modules/plugin/protocol.ts | 0 .../modules/user/components/user-avatar.tsx | 0 .../platform/src/modules/user/index.tsx | 0 .../platform/src/modules/user/module.ts | 0 .../platform/src/modules/user/user-manager.ts | 0 .../src/modules/user/user-protocol.ts | 0 .../platform/src/modules/user/user.ts | 0 .../platform/src/pages/bot/app.ts | 0 .../platform/src/pages/bot/avatar-view.tsx | 0 .../src/pages/bot/base-layout/index.less | 0 .../src/pages/bot/base-layout/layout.tsx | 0 .../src/pages/bot/bot-config/index.less | 0 .../src/pages/bot/bot-config/index.ts | 0 .../src/pages/bot/bot-config/view.tsx | 0 .../src/pages/bot/bot-layout/index.less | 0 .../src/pages/bot/bot-layout/layout.tsx | 0 .../src/pages/bot/bot-persona/index.less | 0 .../src/pages/bot/bot-persona/view.tsx | 0 .../src/pages/bot/bot-previewer/index.less | 0 .../src/pages/bot/bot-previewer/index.ts | 0 .../src/pages/bot/bot-previewer/view.tsx | 0 .../platform/src/pages/bot/bot-provider.ts | 0 .../src/pages/bot/bot-setting/index.less | 0 .../src/pages/bot/bot-setting/index.ts | 0 .../src/pages/bot/bot-setting/view.tsx | 0 .../platform/src/pages/bot/brand/index.less | 0 .../platform/src/pages/bot/brand/logo.svg | 0 .../platform/src/pages/bot/brand/logo.tsx | 0 .../platform/src/pages/bot/brand/view.tsx | 0 .../platform/src/pages/bot/index.tsx | 0 .../src/pages/bot/model-selector/index.less | 0 .../src/pages/bot/model-selector/view.tsx | 0 .../platform/src/pages/bot/module.ts | 0 {web => web-apps}/platform/tsconfig.json | 0 {web => web-apps}/platform/typings.d.ts | 0 {web => web-apps}/platform/typings/index.d.ts | 0 .../platform/umi-plugin-router.ts | 0 {web => web-apps}/ui/.editorconfig | 0 {web => web-apps}/ui/.eslintignore | 0 {web => web-apps}/ui/.eslintrc.json | 0 {web => web-apps}/ui/.eslintrc.mjs | 0 {web => web-apps}/ui/.gitignore | 0 {web => web-apps}/ui/.prettierignore | 0 {web => web-apps}/ui/.prettierrc.json | 0 {web => web-apps}/ui/.stylelintignore | 0 {web => web-apps}/ui/.stylelintrc | 0 {web => web-apps}/ui/README.md | 0 {web => web-apps}/ui/config/config.ts | 0 .../ui/config/dumi-plugin-nodenext.ts | 0 {web => web-apps}/ui/config/routes.ts | 0 .../ui/config/umi-plugin-mana.ts | 0 .../ui/config/umi-plugin-router.ts | 0 {web => web-apps}/ui/package.json | 0 {web => web-apps}/ui/public/favicon.ico | Bin {web => web-apps}/ui/src/app.ts | 0 .../ui/src/common/async-model.ts | 0 .../ui/src/common/page-config.ts | 0 {web => web-apps}/ui/src/common/utils.ts | 0 .../src/components/avatar-upload/index.less | 0 .../ui/src/components/avatar-upload/index.tsx | 0 {web => web-apps}/ui/src/constant/default.ts | 0 .../src/modules/agent/agent-config-manager.ts | 0 .../ui/src/modules/agent/agent-config.ts | 0 .../ui/src/modules/agent/agent-icon.tsx | 0 .../ui/src/modules/agent/agent-manager.ts | 0 .../ui/src/modules/agent/agent-market.ts | 0 .../ui/src/modules/agent/agent-model.ts | 0 .../ui/src/modules/agent/module.ts | 0 .../ui/src/modules/agent/protocol.ts | 0 .../ui/src/modules/app.module.ts | 0 .../ui/src/modules/axios-client/client.ts | 0 .../ui/src/modules/axios-client/module.ts | 0 .../ui/src/modules/axios-client/protocol.ts | 0 .../src/modules/base-layout/back/index.less | 0 .../ui/src/modules/base-layout/back/view.tsx | 0 .../src/modules/base-layout/brand/brand.jpg | Bin .../src/modules/base-layout/brand/index.less | 0 .../ui/src/modules/base-layout/brand/logo.tsx | 0 .../ui/src/modules/base-layout/brand/view.tsx | 0 .../src/modules/base-layout/github/view.tsx | 0 .../ui/src/modules/base-layout/index.less | 0 .../ui/src/modules/base-layout/layout.tsx | 0 .../ui/src/modules/base-layout/main-view.ts | 0 .../ui/src/modules/base-layout/module.ts | 0 .../ui/src/modules/base-layout/page-view.tsx | 0 .../ui/src/modules/base-layout/protocol.ts | 0 .../src/modules/base-layout/title/index.less | 0 .../ui/src/modules/base-layout/title/view.tsx | 0 .../modules/chat-message/ai-message-item.ts | 0 .../modules/chat-message/chat-message-item.ts | 0 .../chat-message/chat-message-manager.ts | 0 .../chat-message/chat-message-model.ts | 0 .../ui/src/modules/chat-message/module.ts | 0 .../chat-message/peer-message-item-model.ts | 0 .../ui/src/modules/chat-message/protocol.ts | 0 .../src/modules/knowledge/knowledge-icon.tsx | 0 .../modules/knowledge/knowledge-manager.ts | 0 .../src/modules/knowledge/knowledge-model.ts | 0 .../src/modules/knowledge/knowledge-space.ts | 0 .../ui/src/modules/knowledge/module.ts | 0 .../ui/src/modules/knowledge/protocol.ts | 0 .../ui/src/modules/model/index.ts | 0 .../ui/src/modules/model/llm-manager.ts | 0 .../ui/src/modules/model/llm-model.ts | 0 .../src/modules/model/model-icon/baichuan.svg | 0 .../src/modules/model/model-icon/deepseek.svg | 0 .../ui/src/modules/model/model-icon/ernie.svg | 0 .../ui/src/modules/model/model-icon/index.tsx | 0 .../src/modules/model/model-icon/moonshot.svg | 0 .../src/modules/model/model-icon/openai.svg | 0 .../ui/src/modules/model/model-icon/qwen.svg | 0 .../ui/src/modules/model/module.ts | 0 .../ui/src/modules/model/protocol.ts | 0 .../ui/src/modules/session/module.ts | 0 .../ui/src/modules/session/protocol.ts | 0 .../ui/src/modules/session/session-manager.ts | 0 .../ui/src/modules/session/session-model.ts | 0 .../ui/src/modules/tool/module.ts | 0 .../ui/src/modules/tool/protocol.ts | 0 .../src/modules/tool/tool-config-manager.ts | 0 .../ui/src/modules/tool/tool-config.ts | 0 .../ui/src/modules/tool/tool-icon.tsx | 0 .../ui/src/modules/tool/tool-manager.ts | 0 .../ui/src/modules/tool/tool-model.ts | 0 .../ui/src/modules/tool/tool-space.ts | 0 .../components/character-setting/index.less | 0 .../components/character-setting/index.tsx | 0 .../components/character-setting/textarea.tsx | 0 .../components/config-selector/index.less | 0 .../components/config-selector/index.tsx | 0 .../components/item-crad/index.less | 0 .../components/item-crad/index.tsx | 0 .../components/model-selector/index.less | 0 .../components/model-selector/index.tsx | 0 .../ui/src/views/agent-config/index.less | 0 .../ui/src/views/agent-config/index.tsx | 0 .../agent-config/knowledge-modal/index.ts | 0 .../agent-config/knowledge-modal/modal.tsx | 0 .../ui/src/views/agent-config/module.ts | 0 .../ui/src/views/agent-config/protocol.ts | 0 .../views/agent-config/tools-modal/index.ts | 0 .../views/agent-config/tools-modal/modal.tsx | 0 .../ui/src/views/agent-config/view.tsx | 0 .../ui/src/views/agent-dev/chat-view.tsx | 0 .../ui/src/views/agent-dev/dev-view.tsx | 0 .../ui/src/views/agent-dev/index.less | 0 .../ui/src/views/agent-dev/index.tsx | 0 .../ui/src/views/agent-dev/module.ts | 0 .../ui/src/views/agent-dev/protocol.ts | 0 .../src/views/agent-flow/agent-flow-view.tsx | 0 .../ui/src/views/agent-flow/flow-dev-view.tsx | 0 .../ui/src/views/agent-flow/index.less | 0 .../ui/src/views/agent-flow/index.tsx | 0 .../ui/src/views/agent-flow/module.ts | 0 .../ui/src/views/agent-flow/protocol.ts | 0 .../ui/src/views/agent-flow/utils.ts | 0 .../ui/src/views/agents/index.less | 0 .../ui/src/views/agents/index.tsx | 0 .../ui/src/views/agents/modal/contribution.ts | 0 .../ui/src/views/agents/modal/create.tsx | 0 .../ui/src/views/agents/modal/index.less | 0 .../ui/src/views/agents/module.ts | 0 .../ui/src/views/agents/view.tsx | 0 .../src/views/chat/components/input/icon.tsx | 0 .../views/chat/components/input/index.less | 0 .../src/views/chat/components/input/index.tsx | 0 .../chat/components/message/ai-message.tsx | 0 .../chat/components/message/exchange.tsx | 0 .../chat/components/message/human-message.tsx | 0 .../views/chat/components/message/index.less | 0 .../components/message/markdown/index.less | 0 .../components/message/markdown/index.tsx | 0 .../markdown/modules/CodeBlock/index.less | 0 .../markdown/modules/CodeBlock/index.tsx | 0 .../views/chat/components/message/message.tsx | 0 .../chat/components/message/peer-message.tsx | 0 .../views/chat/components/message/peer.less | 0 .../chat/components/message/text/index.less | 0 .../chat/components/message/text/index.tsx | 0 .../views/chat/components/typing/index.less | 0 .../views/chat/components/typing/index.tsx | 0 .../ui/src/views/chat/index.less | 0 web-apps/ui/src/views/chat/index.ts | 6 + {web => web-apps}/ui/src/views/chat/module.ts | 0 {web => web-apps}/ui/src/views/chat/view.tsx | 0 .../views/debug/debug-drawer-contribution.ts | 0 .../ui/src/views/debug/debug-drawer.tsx | 0 .../ui/src/views/debug/module.ts | 0 .../ui/src/views/debug/protocol.ts | 0 .../ui/src/views/knowledge/index.less | 0 .../ui/src/views/knowledge/index.tsx | 0 .../ui/src/views/knowledge/module.ts | 0 .../ui/src/views/knowledge/view.tsx | 0 .../ui/src/views/protal-layout/index.less | 0 .../ui/src/views/protal-layout/index.ts | 0 .../ui/src/views/protal-layout/module.ts | 0 .../ui/src/views/protal-layout/protocol.ts | 0 .../ui/src/views/protal-layout/view.tsx | 0 .../sessions/conversation-list/index.less | 0 .../sessions/conversation-list/index.tsx | 0 .../ui/src/views/sessions/index.less | 0 .../ui/src/views/sessions/module.ts | 0 .../ui/src/views/sessions/view.tsx | 0 .../ui/src/views/tools/index.less | 0 .../ui/src/views/tools/index.tsx | 0 .../ui/src/views/tools/module.ts | 0 {web => web-apps}/ui/src/views/tools/view.tsx | 0 {web => web-apps}/ui/tsconfig.json | 0 {web => web-apps}/ui/typings.d.ts | 0 {web => web-apps}/ui/typings/index.d.ts | 0 .../magent-core/.eslintrc.mjs | 0 .../magent-core/.fatherrc.ts | 0 .../magent-core/CHANGELOG.md | 0 .../magent-core/README.md | 0 .../magent-core/babel.config.json | 0 .../magent-core/jest.config.mjs | 0 .../magent-core/package.json | 0 .../magent-core/src/index.spec.ts | 0 .../magent-core/src/index.ts | 0 .../magent-core/tsconfig.json | 7 +- .../magent-flow/.eslintrc.mjs | 0 .../magent-flow/.fatherrc.ts | 0 .../magent-flow/.gitignore | 0 .../magent-flow/.stylelintignore | 0 web-packages/magent-flow/CHANGELOG.md | 0 .../magent-flow/README.md | 0 web-packages/magent-flow/babel.config.json | 13 + .../magent-flow/jest.config.mjs | 0 .../magent-flow/package.json | 7 +- .../magent-flow/src/FormSchema/index.ts | 0 .../magent-flow/src/RefForm/index.md | 0 .../magent-flow/src/RefForm/index.tsx | 0 .../magent-flow/src/SchemaConfigForm/index.md | 0 .../src/SchemaConfigForm/index.tsx | 0 .../magent-flow/src/common/icons.ts | 0 .../AIBasic/CascaderInNode/index.tsx | 0 .../AIBasic/CollapseWrapper/index.tsx | 0 .../OutputVariable/index.tsx | 0 .../AIBasic/PromptEditor/constants.tsx | 0 .../components/AIBasic/PromptEditor/hooks.ts | 0 .../components/AIBasic/PromptEditor/index.tsx | 0 .../plugins/component-picker-block/hooks.tsx | 0 .../plugins/component-picker-block/index.tsx | 0 .../plugins/component-picker-block/menu.tsx | 0 .../component-picker-block/prompt-option.tsx | 0 .../variable-option.tsx | 0 .../PromptEditor/plugins/custom-text/node.tsx | 0 .../plugins/on-blur-or-focus-block.tsx | 0 .../PromptEditor/plugins/placeholder.tsx | 0 .../PromptEditor/plugins/update-block.tsx | 0 .../plugins/variable-block/index.tsx | 0 .../plugins/variable-value-block/index.tsx | 0 .../plugins/variable-value-block/node.tsx | 0 .../plugins/variable-value-block/utils.ts | 0 .../components/AIBasic/PromptEditor/types.ts | 0 .../components/AIBasic/PromptEditor/utils.ts | 0 .../components/AIBasic/SelectInNode/index.tsx | 0 .../src/components/CustomEdge/index.tsx | 0 .../magent-flow/src/components/Flow/index.tsx | 0 .../magent-flow/src/components/Flow/keys.ts | 0 .../src/components/FlowController/index.tsx | 0 .../src/components/FlowWithPanel/index.tsx | 0 .../FlowWithPanel/nodeTemplate.yaml | 0 .../src/components/Node/AgentNode/index.tsx | 0 .../src/components/Node/CommonNode/index.tsx | 0 .../src/components/Node/EndNode/index.tsx | 0 .../src/components/Node/IfElseNode/index.tsx | 0 .../components/Node/KnowledgeNode/index.tsx | 0 .../src/components/Node/LLMNode/index.tsx | 0 .../Node/NodeWrapper/Header/index.tsx | 0 .../Node/NodeWrapper/Status/index.tsx | 0 .../src/components/Node/NodeWrapper/index.tsx | 0 .../src/components/Node/StartNode/index.tsx | 0 .../magent-flow/src/components/Node/index.tsx | 0 .../src/components/NodePanel/index.tsx | 0 .../src/components/RefForm/index.md | 0 .../src/components/ReferenceForm/index.tsx | 0 .../src/components/ReferenceSelect/index.tsx | 0 .../src/components/VariableForm/index.tsx | 0 .../magent-flow/src/constants/constant.ts | 0 .../magent-flow/src/context/event-emitter.tsx | 0 .../magent-flow/src/index.ts | 0 .../magent-flow/src/interfaces/flow.ts | 0 .../magent-flow/src/spec/FormSchema/index.ts | 0 .../src/spec/__snapshots__/node.test.ts.snap | 0 .../magent-flow/src/spec/node.test.ts | 0 .../magent-flow/src/spec/node.ts | 0 .../magent-flow/src/spec/test-jsonschema.json | 0 .../magent-flow/src/spec/uuid.ts | 0 .../magent-flow/src/stores/useFlowStore.ts | 0 .../src/stores/useKnowledgeStore.ts | 0 .../magent-flow/src/stores/useModelStore.ts | 0 .../src/stores/useShortcutsStore.ts | 0 .../src/stores/useUndoRedoStore.ts | 0 .../magent-flow/src/tailwind.css | 0 .../magent-flow/src/utils/basic.ts | 0 .../magent-flow/src/utils/index.tsx | 0 .../magent-flow/src/utils/reactflowUtils.ts | 0 .../magent-flow/src/utils/wrappedClass.ts | 0 .../magent-flow/tailwind.config.js | 0 .../magent-flow/tsconfig.json | 2 +- web/packages/magent-core/CHANGELOG.md | 402 ------------------ web/packages/magent-flow/CHANGELOG.md | 402 ------------------ web/packages/magent-flow/babel.config.json | 20 - web/ui/src/views/chat/index.ts | 6 - 376 files changed, 30 insertions(+), 841 deletions(-) rename {web => web-apps}/platform/.editorconfig (100%) rename {web => web-apps}/platform/.eslintignore (100%) rename {web => web-apps}/platform/.eslintrc.json (100%) rename {web => web-apps}/platform/.eslintrc.mjs (100%) rename {web => web-apps}/platform/.gitignore (100%) rename {web => web-apps}/platform/.prettierignore (100%) rename {web => web-apps}/platform/.prettierrc.json (100%) rename {web => web-apps}/platform/.stylelintignore (100%) rename {web => web-apps}/platform/.stylelintrc (100%) rename {web => web-apps}/platform/.umirc.ts (100%) rename {web => web-apps}/platform/README.md (100%) rename {web => web-apps}/platform/dumi-plugin-nodenext.ts (100%) rename {web => web-apps}/platform/package.json (100%) rename {web => web-apps}/platform/public/favicon.ico (100%) rename {web => web-apps}/platform/routes.ts (100%) rename {web => web-apps}/platform/src/app.ts (100%) rename {web => web-apps}/platform/src/common/async-model.ts (100%) rename {web => web-apps}/platform/src/constant/default.ts (100%) rename {web => web-apps}/platform/src/modules/agent-bot/agent-bot-manager.ts (100%) rename {web => web-apps}/platform/src/modules/agent-bot/agent-bot.ts (100%) rename {web => web-apps}/platform/src/modules/agent-bot/agent-config-manager.ts (100%) rename {web => web-apps}/platform/src/modules/agent-bot/agent-config.ts (100%) rename {web => web-apps}/platform/src/modules/agent-bot/index.ts (100%) rename {web => web-apps}/platform/src/modules/agent-bot/module.ts (100%) rename {web => web-apps}/platform/src/modules/agent-bot/protocol.ts (100%) rename {web => web-apps}/platform/src/modules/agent-module.ts (100%) rename {web => web-apps}/platform/src/modules/app.module.ts (100%) rename {web => web-apps}/platform/src/modules/axios-client/client.ts (100%) rename {web => web-apps}/platform/src/modules/axios-client/index.ts (100%) rename {web => web-apps}/platform/src/modules/axios-client/module.ts (100%) rename {web => web-apps}/platform/src/modules/axios-client/protocol.ts (100%) rename {web => web-apps}/platform/src/modules/chat/chat-message.ts (100%) rename {web => web-apps}/platform/src/modules/chat/chat-turn.ts (100%) rename {web => web-apps}/platform/src/modules/chat/chat.ts (100%) rename {web => web-apps}/platform/src/modules/chat/components/chat.tsx (100%) rename {web => web-apps}/platform/src/modules/chat/components/index.less (100%) rename {web => web-apps}/platform/src/modules/chat/components/input/icon.tsx (100%) rename {web => web-apps}/platform/src/modules/chat/components/input/index.less (100%) rename {web => web-apps}/platform/src/modules/chat/components/input/index.tsx (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/group.tsx (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/index.less (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/markdown-message/index.less (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/markdown-message/index.tsx (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/markdown/index.less (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/markdown/index.tsx (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/markdown/modules/CodeBlock/index.less (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/markdown/modules/CodeBlock/index.tsx (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/message.tsx (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/text/index.less (100%) rename {web => web-apps}/platform/src/modules/chat/components/message/text/index.tsx (100%) rename {web => web-apps}/platform/src/modules/chat/components/typing/index.less (100%) rename {web => web-apps}/platform/src/modules/chat/components/typing/index.tsx (100%) rename {web => web-apps}/platform/src/modules/chat/index.ts (100%) rename {web => web-apps}/platform/src/modules/chat/manager.ts (100%) rename {web => web-apps}/platform/src/modules/chat/message-manager.ts (100%) rename {web => web-apps}/platform/src/modules/chat/module.ts (100%) rename {web => web-apps}/platform/src/modules/chat/protocol.ts (100%) rename {web => web-apps}/platform/src/modules/model/built-in-model-meta.ts (100%) rename {web => web-apps}/platform/src/modules/model/index.ts (100%) rename {web => web-apps}/platform/src/modules/model/model-manager.ts (100%) rename {web => web-apps}/platform/src/modules/model/model.ts (100%) rename {web => web-apps}/platform/src/modules/model/module.ts (100%) rename {web => web-apps}/platform/src/modules/model/protocol.ts (100%) rename {web => web-apps}/platform/src/modules/plugin/index.ts (100%) rename {web => web-apps}/platform/src/modules/plugin/module.ts (100%) rename {web => web-apps}/platform/src/modules/plugin/plugin-config-manager.ts (100%) rename {web => web-apps}/platform/src/modules/plugin/plugin-config.ts (100%) rename {web => web-apps}/platform/src/modules/plugin/plugin-manager.ts (100%) rename {web => web-apps}/platform/src/modules/plugin/plugin.ts (100%) rename {web => web-apps}/platform/src/modules/plugin/protocol.ts (100%) rename {web => web-apps}/platform/src/modules/user/components/user-avatar.tsx (100%) rename {web => web-apps}/platform/src/modules/user/index.tsx (100%) rename {web => web-apps}/platform/src/modules/user/module.ts (100%) rename {web => web-apps}/platform/src/modules/user/user-manager.ts (100%) rename {web => web-apps}/platform/src/modules/user/user-protocol.ts (100%) rename {web => web-apps}/platform/src/modules/user/user.ts (100%) rename {web => web-apps}/platform/src/pages/bot/app.ts (100%) rename {web => web-apps}/platform/src/pages/bot/avatar-view.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/base-layout/index.less (100%) rename {web => web-apps}/platform/src/pages/bot/base-layout/layout.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/bot-config/index.less (100%) rename {web => web-apps}/platform/src/pages/bot/bot-config/index.ts (100%) rename {web => web-apps}/platform/src/pages/bot/bot-config/view.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/bot-layout/index.less (100%) rename {web => web-apps}/platform/src/pages/bot/bot-layout/layout.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/bot-persona/index.less (100%) rename {web => web-apps}/platform/src/pages/bot/bot-persona/view.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/bot-previewer/index.less (100%) rename {web => web-apps}/platform/src/pages/bot/bot-previewer/index.ts (100%) rename {web => web-apps}/platform/src/pages/bot/bot-previewer/view.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/bot-provider.ts (100%) rename {web => web-apps}/platform/src/pages/bot/bot-setting/index.less (100%) rename {web => web-apps}/platform/src/pages/bot/bot-setting/index.ts (100%) rename {web => web-apps}/platform/src/pages/bot/bot-setting/view.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/brand/index.less (100%) rename {web => web-apps}/platform/src/pages/bot/brand/logo.svg (100%) rename {web => web-apps}/platform/src/pages/bot/brand/logo.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/brand/view.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/index.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/model-selector/index.less (100%) rename {web => web-apps}/platform/src/pages/bot/model-selector/view.tsx (100%) rename {web => web-apps}/platform/src/pages/bot/module.ts (100%) rename {web => web-apps}/platform/tsconfig.json (100%) rename {web => web-apps}/platform/typings.d.ts (100%) rename {web => web-apps}/platform/typings/index.d.ts (100%) rename {web => web-apps}/platform/umi-plugin-router.ts (100%) rename {web => web-apps}/ui/.editorconfig (100%) rename {web => web-apps}/ui/.eslintignore (100%) rename {web => web-apps}/ui/.eslintrc.json (100%) rename {web => web-apps}/ui/.eslintrc.mjs (100%) rename {web => web-apps}/ui/.gitignore (100%) rename {web => web-apps}/ui/.prettierignore (100%) rename {web => web-apps}/ui/.prettierrc.json (100%) rename {web => web-apps}/ui/.stylelintignore (100%) rename {web => web-apps}/ui/.stylelintrc (100%) rename {web => web-apps}/ui/README.md (100%) rename {web => web-apps}/ui/config/config.ts (100%) rename {web => web-apps}/ui/config/dumi-plugin-nodenext.ts (100%) rename {web => web-apps}/ui/config/routes.ts (100%) rename {web => web-apps}/ui/config/umi-plugin-mana.ts (100%) rename {web => web-apps}/ui/config/umi-plugin-router.ts (100%) rename {web => web-apps}/ui/package.json (100%) rename {web => web-apps}/ui/public/favicon.ico (100%) rename {web => web-apps}/ui/src/app.ts (100%) rename {web => web-apps}/ui/src/common/async-model.ts (100%) rename {web => web-apps}/ui/src/common/page-config.ts (100%) rename {web => web-apps}/ui/src/common/utils.ts (100%) rename {web => web-apps}/ui/src/components/avatar-upload/index.less (100%) rename {web => web-apps}/ui/src/components/avatar-upload/index.tsx (100%) rename {web => web-apps}/ui/src/constant/default.ts (100%) rename {web => web-apps}/ui/src/modules/agent/agent-config-manager.ts (100%) rename {web => web-apps}/ui/src/modules/agent/agent-config.ts (100%) rename {web => web-apps}/ui/src/modules/agent/agent-icon.tsx (100%) rename {web => web-apps}/ui/src/modules/agent/agent-manager.ts (100%) rename {web => web-apps}/ui/src/modules/agent/agent-market.ts (100%) rename {web => web-apps}/ui/src/modules/agent/agent-model.ts (100%) rename {web => web-apps}/ui/src/modules/agent/module.ts (100%) rename {web => web-apps}/ui/src/modules/agent/protocol.ts (100%) rename {web => web-apps}/ui/src/modules/app.module.ts (100%) rename {web => web-apps}/ui/src/modules/axios-client/client.ts (100%) rename {web => web-apps}/ui/src/modules/axios-client/module.ts (100%) rename {web => web-apps}/ui/src/modules/axios-client/protocol.ts (100%) rename {web => web-apps}/ui/src/modules/base-layout/back/index.less (100%) rename {web => web-apps}/ui/src/modules/base-layout/back/view.tsx (100%) rename {web => web-apps}/ui/src/modules/base-layout/brand/brand.jpg (100%) rename {web => web-apps}/ui/src/modules/base-layout/brand/index.less (100%) rename {web => web-apps}/ui/src/modules/base-layout/brand/logo.tsx (100%) rename {web => web-apps}/ui/src/modules/base-layout/brand/view.tsx (100%) rename {web => web-apps}/ui/src/modules/base-layout/github/view.tsx (100%) rename {web => web-apps}/ui/src/modules/base-layout/index.less (100%) rename {web => web-apps}/ui/src/modules/base-layout/layout.tsx (100%) rename {web => web-apps}/ui/src/modules/base-layout/main-view.ts (100%) rename {web => web-apps}/ui/src/modules/base-layout/module.ts (100%) rename {web => web-apps}/ui/src/modules/base-layout/page-view.tsx (100%) rename {web => web-apps}/ui/src/modules/base-layout/protocol.ts (100%) rename {web => web-apps}/ui/src/modules/base-layout/title/index.less (100%) rename {web => web-apps}/ui/src/modules/base-layout/title/view.tsx (100%) rename {web => web-apps}/ui/src/modules/chat-message/ai-message-item.ts (100%) rename {web => web-apps}/ui/src/modules/chat-message/chat-message-item.ts (100%) rename {web => web-apps}/ui/src/modules/chat-message/chat-message-manager.ts (100%) rename {web => web-apps}/ui/src/modules/chat-message/chat-message-model.ts (100%) rename {web => web-apps}/ui/src/modules/chat-message/module.ts (100%) rename {web => web-apps}/ui/src/modules/chat-message/peer-message-item-model.ts (100%) rename {web => web-apps}/ui/src/modules/chat-message/protocol.ts (100%) rename {web => web-apps}/ui/src/modules/knowledge/knowledge-icon.tsx (100%) rename {web => web-apps}/ui/src/modules/knowledge/knowledge-manager.ts (100%) rename {web => web-apps}/ui/src/modules/knowledge/knowledge-model.ts (100%) rename {web => web-apps}/ui/src/modules/knowledge/knowledge-space.ts (100%) rename {web => web-apps}/ui/src/modules/knowledge/module.ts (100%) rename {web => web-apps}/ui/src/modules/knowledge/protocol.ts (100%) rename {web => web-apps}/ui/src/modules/model/index.ts (100%) rename {web => web-apps}/ui/src/modules/model/llm-manager.ts (100%) rename {web => web-apps}/ui/src/modules/model/llm-model.ts (100%) rename {web => web-apps}/ui/src/modules/model/model-icon/baichuan.svg (100%) rename {web => web-apps}/ui/src/modules/model/model-icon/deepseek.svg (100%) rename {web => web-apps}/ui/src/modules/model/model-icon/ernie.svg (100%) rename {web => web-apps}/ui/src/modules/model/model-icon/index.tsx (100%) rename {web => web-apps}/ui/src/modules/model/model-icon/moonshot.svg (100%) rename {web => web-apps}/ui/src/modules/model/model-icon/openai.svg (100%) rename {web => web-apps}/ui/src/modules/model/model-icon/qwen.svg (100%) rename {web => web-apps}/ui/src/modules/model/module.ts (100%) rename {web => web-apps}/ui/src/modules/model/protocol.ts (100%) rename {web => web-apps}/ui/src/modules/session/module.ts (100%) rename {web => web-apps}/ui/src/modules/session/protocol.ts (100%) rename {web => web-apps}/ui/src/modules/session/session-manager.ts (100%) rename {web => web-apps}/ui/src/modules/session/session-model.ts (100%) rename {web => web-apps}/ui/src/modules/tool/module.ts (100%) rename {web => web-apps}/ui/src/modules/tool/protocol.ts (100%) rename {web => web-apps}/ui/src/modules/tool/tool-config-manager.ts (100%) rename {web => web-apps}/ui/src/modules/tool/tool-config.ts (100%) rename {web => web-apps}/ui/src/modules/tool/tool-icon.tsx (100%) rename {web => web-apps}/ui/src/modules/tool/tool-manager.ts (100%) rename {web => web-apps}/ui/src/modules/tool/tool-model.ts (100%) rename {web => web-apps}/ui/src/modules/tool/tool-space.ts (100%) rename {web => web-apps}/ui/src/views/agent-config/components/character-setting/index.less (100%) rename {web => web-apps}/ui/src/views/agent-config/components/character-setting/index.tsx (100%) rename {web => web-apps}/ui/src/views/agent-config/components/character-setting/textarea.tsx (100%) rename {web => web-apps}/ui/src/views/agent-config/components/config-selector/index.less (100%) rename {web => web-apps}/ui/src/views/agent-config/components/config-selector/index.tsx (100%) rename {web => web-apps}/ui/src/views/agent-config/components/item-crad/index.less (100%) rename {web => web-apps}/ui/src/views/agent-config/components/item-crad/index.tsx (100%) rename {web => web-apps}/ui/src/views/agent-config/components/model-selector/index.less (100%) rename {web => web-apps}/ui/src/views/agent-config/components/model-selector/index.tsx (100%) rename {web => web-apps}/ui/src/views/agent-config/index.less (100%) rename {web => web-apps}/ui/src/views/agent-config/index.tsx (100%) rename {web => web-apps}/ui/src/views/agent-config/knowledge-modal/index.ts (100%) rename {web => web-apps}/ui/src/views/agent-config/knowledge-modal/modal.tsx (100%) rename {web => web-apps}/ui/src/views/agent-config/module.ts (100%) rename {web => web-apps}/ui/src/views/agent-config/protocol.ts (100%) rename {web => web-apps}/ui/src/views/agent-config/tools-modal/index.ts (100%) rename {web => web-apps}/ui/src/views/agent-config/tools-modal/modal.tsx (100%) rename {web => web-apps}/ui/src/views/agent-config/view.tsx (100%) rename {web => web-apps}/ui/src/views/agent-dev/chat-view.tsx (100%) rename {web => web-apps}/ui/src/views/agent-dev/dev-view.tsx (100%) rename {web => web-apps}/ui/src/views/agent-dev/index.less (100%) rename {web => web-apps}/ui/src/views/agent-dev/index.tsx (100%) rename {web => web-apps}/ui/src/views/agent-dev/module.ts (100%) rename {web => web-apps}/ui/src/views/agent-dev/protocol.ts (100%) rename {web => web-apps}/ui/src/views/agent-flow/agent-flow-view.tsx (100%) rename {web => web-apps}/ui/src/views/agent-flow/flow-dev-view.tsx (100%) rename {web => web-apps}/ui/src/views/agent-flow/index.less (100%) rename {web => web-apps}/ui/src/views/agent-flow/index.tsx (100%) rename {web => web-apps}/ui/src/views/agent-flow/module.ts (100%) rename {web => web-apps}/ui/src/views/agent-flow/protocol.ts (100%) rename {web => web-apps}/ui/src/views/agent-flow/utils.ts (100%) rename {web => web-apps}/ui/src/views/agents/index.less (100%) rename {web => web-apps}/ui/src/views/agents/index.tsx (100%) rename {web => web-apps}/ui/src/views/agents/modal/contribution.ts (100%) rename {web => web-apps}/ui/src/views/agents/modal/create.tsx (100%) rename {web => web-apps}/ui/src/views/agents/modal/index.less (100%) rename {web => web-apps}/ui/src/views/agents/module.ts (100%) rename {web => web-apps}/ui/src/views/agents/view.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/input/icon.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/input/index.less (100%) rename {web => web-apps}/ui/src/views/chat/components/input/index.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/message/ai-message.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/message/exchange.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/message/human-message.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/message/index.less (100%) rename {web => web-apps}/ui/src/views/chat/components/message/markdown/index.less (100%) rename {web => web-apps}/ui/src/views/chat/components/message/markdown/index.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/message/markdown/modules/CodeBlock/index.less (100%) rename {web => web-apps}/ui/src/views/chat/components/message/markdown/modules/CodeBlock/index.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/message/message.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/message/peer-message.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/message/peer.less (100%) rename {web => web-apps}/ui/src/views/chat/components/message/text/index.less (100%) rename {web => web-apps}/ui/src/views/chat/components/message/text/index.tsx (100%) rename {web => web-apps}/ui/src/views/chat/components/typing/index.less (100%) rename {web => web-apps}/ui/src/views/chat/components/typing/index.tsx (100%) rename {web => web-apps}/ui/src/views/chat/index.less (100%) create mode 100644 web-apps/ui/src/views/chat/index.ts rename {web => web-apps}/ui/src/views/chat/module.ts (100%) rename {web => web-apps}/ui/src/views/chat/view.tsx (100%) rename {web => web-apps}/ui/src/views/debug/debug-drawer-contribution.ts (100%) rename {web => web-apps}/ui/src/views/debug/debug-drawer.tsx (100%) rename {web => web-apps}/ui/src/views/debug/module.ts (100%) rename {web => web-apps}/ui/src/views/debug/protocol.ts (100%) rename {web => web-apps}/ui/src/views/knowledge/index.less (100%) rename {web => web-apps}/ui/src/views/knowledge/index.tsx (100%) rename {web => web-apps}/ui/src/views/knowledge/module.ts (100%) rename {web => web-apps}/ui/src/views/knowledge/view.tsx (100%) rename {web => web-apps}/ui/src/views/protal-layout/index.less (100%) rename {web => web-apps}/ui/src/views/protal-layout/index.ts (100%) rename {web => web-apps}/ui/src/views/protal-layout/module.ts (100%) rename {web => web-apps}/ui/src/views/protal-layout/protocol.ts (100%) rename {web => web-apps}/ui/src/views/protal-layout/view.tsx (100%) rename {web => web-apps}/ui/src/views/sessions/conversation-list/index.less (100%) rename {web => web-apps}/ui/src/views/sessions/conversation-list/index.tsx (100%) rename {web => web-apps}/ui/src/views/sessions/index.less (100%) rename {web => web-apps}/ui/src/views/sessions/module.ts (100%) rename {web => web-apps}/ui/src/views/sessions/view.tsx (100%) rename {web => web-apps}/ui/src/views/tools/index.less (100%) rename {web => web-apps}/ui/src/views/tools/index.tsx (100%) rename {web => web-apps}/ui/src/views/tools/module.ts (100%) rename {web => web-apps}/ui/src/views/tools/view.tsx (100%) rename {web => web-apps}/ui/tsconfig.json (100%) rename {web => web-apps}/ui/typings.d.ts (100%) rename {web => web-apps}/ui/typings/index.d.ts (100%) rename {web/packages => web-packages}/magent-core/.eslintrc.mjs (100%) rename {web/packages => web-packages}/magent-core/.fatherrc.ts (100%) rename web/packages/magent-flow/src/components/Node/index.tsx => web-packages/magent-core/CHANGELOG.md (100%) rename {web/packages => web-packages}/magent-core/README.md (100%) rename {web/packages => web-packages}/magent-core/babel.config.json (100%) rename {web/packages => web-packages}/magent-core/jest.config.mjs (100%) rename {web/packages => web-packages}/magent-core/package.json (100%) rename {web/packages => web-packages}/magent-core/src/index.spec.ts (100%) rename {web/packages => web-packages}/magent-core/src/index.ts (100%) rename {web/packages => web-packages}/magent-core/tsconfig.json (53%) rename {web/packages => web-packages}/magent-flow/.eslintrc.mjs (100%) rename {web/packages => web-packages}/magent-flow/.fatherrc.ts (100%) rename {web/packages => web-packages}/magent-flow/.gitignore (100%) rename {web/packages => web-packages}/magent-flow/.stylelintignore (100%) create mode 100644 web-packages/magent-flow/CHANGELOG.md rename {web/packages => web-packages}/magent-flow/README.md (100%) create mode 100644 web-packages/magent-flow/babel.config.json rename {web/packages => web-packages}/magent-flow/jest.config.mjs (100%) rename {web/packages => web-packages}/magent-flow/package.json (92%) rename {web/packages => web-packages}/magent-flow/src/FormSchema/index.ts (100%) rename {web/packages => web-packages}/magent-flow/src/RefForm/index.md (100%) rename {web/packages => web-packages}/magent-flow/src/RefForm/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/SchemaConfigForm/index.md (100%) rename {web/packages => web-packages}/magent-flow/src/SchemaConfigForm/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/common/icons.ts (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/CollapseWrapper/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/constants.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/menu.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/utils.ts (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/types.ts (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/PromptEditor/utils.ts (100%) rename {web/packages => web-packages}/magent-flow/src/components/AIBasic/SelectInNode/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/CustomEdge/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Flow/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Flow/keys.ts (100%) rename {web/packages => web-packages}/magent-flow/src/components/FlowController/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/FlowWithPanel/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml (100%) rename {web/packages => web-packages}/magent-flow/src/components/Node/AgentNode/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Node/CommonNode/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Node/EndNode/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Node/IfElseNode/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Node/KnowledgeNode/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Node/LLMNode/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Node/NodeWrapper/Header/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Node/NodeWrapper/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/Node/StartNode/index.tsx (100%) create mode 100644 web-packages/magent-flow/src/components/Node/index.tsx rename {web/packages => web-packages}/magent-flow/src/components/NodePanel/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/RefForm/index.md (100%) rename {web/packages => web-packages}/magent-flow/src/components/ReferenceForm/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/ReferenceSelect/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/VariableForm/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/constants/constant.ts (100%) rename {web/packages => web-packages}/magent-flow/src/context/event-emitter.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/index.ts (100%) rename {web/packages => web-packages}/magent-flow/src/interfaces/flow.ts (100%) rename {web/packages => web-packages}/magent-flow/src/spec/FormSchema/index.ts (100%) rename {web/packages => web-packages}/magent-flow/src/spec/__snapshots__/node.test.ts.snap (100%) rename {web/packages => web-packages}/magent-flow/src/spec/node.test.ts (100%) rename {web/packages => web-packages}/magent-flow/src/spec/node.ts (100%) rename {web/packages => web-packages}/magent-flow/src/spec/test-jsonschema.json (100%) rename {web/packages => web-packages}/magent-flow/src/spec/uuid.ts (100%) rename {web/packages => web-packages}/magent-flow/src/stores/useFlowStore.ts (100%) rename {web/packages => web-packages}/magent-flow/src/stores/useKnowledgeStore.ts (100%) rename {web/packages => web-packages}/magent-flow/src/stores/useModelStore.ts (100%) rename {web/packages => web-packages}/magent-flow/src/stores/useShortcutsStore.ts (100%) rename {web/packages => web-packages}/magent-flow/src/stores/useUndoRedoStore.ts (100%) rename {web/packages => web-packages}/magent-flow/src/tailwind.css (100%) rename {web/packages => web-packages}/magent-flow/src/utils/basic.ts (100%) rename {web/packages => web-packages}/magent-flow/src/utils/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/utils/reactflowUtils.ts (100%) rename {web/packages => web-packages}/magent-flow/src/utils/wrappedClass.ts (100%) rename {web/packages => web-packages}/magent-flow/tailwind.config.js (100%) rename {web/packages => web-packages}/magent-flow/tsconfig.json (83%) delete mode 100644 web/packages/magent-core/CHANGELOG.md delete mode 100644 web/packages/magent-flow/CHANGELOG.md delete mode 100644 web/packages/magent-flow/babel.config.json delete mode 100644 web/ui/src/views/chat/index.ts diff --git a/.prettierignore b/.prettierignore index 7dc1479..aa27505 100644 --- a/.prettierignore +++ b/.prettierignore @@ -12,6 +12,7 @@ pnpm-lock.yaml # generated code **/.dumi/tmp **/.dumi/tmp-production +**/.umi-production **/.docusaurus **/.umi diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 67bda7d..00860ab 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,5 +1,4 @@ packages: - - 'web/platform' - - 'web/ui' - - 'web/packages/*' + - 'web-apps/*' + - 'web-packages/*' - 'docs/site' diff --git a/web/platform/.editorconfig b/web-apps/platform/.editorconfig similarity index 100% rename from web/platform/.editorconfig rename to web-apps/platform/.editorconfig diff --git a/web/platform/.eslintignore b/web-apps/platform/.eslintignore similarity index 100% rename from web/platform/.eslintignore rename to web-apps/platform/.eslintignore diff --git a/web/platform/.eslintrc.json b/web-apps/platform/.eslintrc.json similarity index 100% rename from web/platform/.eslintrc.json rename to web-apps/platform/.eslintrc.json diff --git a/web/platform/.eslintrc.mjs b/web-apps/platform/.eslintrc.mjs similarity index 100% rename from web/platform/.eslintrc.mjs rename to web-apps/platform/.eslintrc.mjs diff --git a/web/platform/.gitignore b/web-apps/platform/.gitignore similarity index 100% rename from web/platform/.gitignore rename to web-apps/platform/.gitignore diff --git a/web/platform/.prettierignore b/web-apps/platform/.prettierignore similarity index 100% rename from web/platform/.prettierignore rename to web-apps/platform/.prettierignore diff --git a/web/platform/.prettierrc.json b/web-apps/platform/.prettierrc.json similarity index 100% rename from web/platform/.prettierrc.json rename to web-apps/platform/.prettierrc.json diff --git a/web/platform/.stylelintignore b/web-apps/platform/.stylelintignore similarity index 100% rename from web/platform/.stylelintignore rename to web-apps/platform/.stylelintignore diff --git a/web/platform/.stylelintrc b/web-apps/platform/.stylelintrc similarity index 100% rename from web/platform/.stylelintrc rename to web-apps/platform/.stylelintrc diff --git a/web/platform/.umirc.ts b/web-apps/platform/.umirc.ts similarity index 100% rename from web/platform/.umirc.ts rename to web-apps/platform/.umirc.ts diff --git a/web/platform/README.md b/web-apps/platform/README.md similarity index 100% rename from web/platform/README.md rename to web-apps/platform/README.md diff --git a/web/platform/dumi-plugin-nodenext.ts b/web-apps/platform/dumi-plugin-nodenext.ts similarity index 100% rename from web/platform/dumi-plugin-nodenext.ts rename to web-apps/platform/dumi-plugin-nodenext.ts diff --git a/web/platform/package.json b/web-apps/platform/package.json similarity index 100% rename from web/platform/package.json rename to web-apps/platform/package.json diff --git a/web/platform/public/favicon.ico b/web-apps/platform/public/favicon.ico similarity index 100% rename from web/platform/public/favicon.ico rename to web-apps/platform/public/favicon.ico diff --git a/web/platform/routes.ts b/web-apps/platform/routes.ts similarity index 100% rename from web/platform/routes.ts rename to web-apps/platform/routes.ts diff --git a/web/platform/src/app.ts b/web-apps/platform/src/app.ts similarity index 100% rename from web/platform/src/app.ts rename to web-apps/platform/src/app.ts diff --git a/web/platform/src/common/async-model.ts b/web-apps/platform/src/common/async-model.ts similarity index 100% rename from web/platform/src/common/async-model.ts rename to web-apps/platform/src/common/async-model.ts diff --git a/web/platform/src/constant/default.ts b/web-apps/platform/src/constant/default.ts similarity index 100% rename from web/platform/src/constant/default.ts rename to web-apps/platform/src/constant/default.ts diff --git a/web/platform/src/modules/agent-bot/agent-bot-manager.ts b/web-apps/platform/src/modules/agent-bot/agent-bot-manager.ts similarity index 100% rename from web/platform/src/modules/agent-bot/agent-bot-manager.ts rename to web-apps/platform/src/modules/agent-bot/agent-bot-manager.ts diff --git a/web/platform/src/modules/agent-bot/agent-bot.ts b/web-apps/platform/src/modules/agent-bot/agent-bot.ts similarity index 100% rename from web/platform/src/modules/agent-bot/agent-bot.ts rename to web-apps/platform/src/modules/agent-bot/agent-bot.ts diff --git a/web/platform/src/modules/agent-bot/agent-config-manager.ts b/web-apps/platform/src/modules/agent-bot/agent-config-manager.ts similarity index 100% rename from web/platform/src/modules/agent-bot/agent-config-manager.ts rename to web-apps/platform/src/modules/agent-bot/agent-config-manager.ts diff --git a/web/platform/src/modules/agent-bot/agent-config.ts b/web-apps/platform/src/modules/agent-bot/agent-config.ts similarity index 100% rename from web/platform/src/modules/agent-bot/agent-config.ts rename to web-apps/platform/src/modules/agent-bot/agent-config.ts diff --git a/web/platform/src/modules/agent-bot/index.ts b/web-apps/platform/src/modules/agent-bot/index.ts similarity index 100% rename from web/platform/src/modules/agent-bot/index.ts rename to web-apps/platform/src/modules/agent-bot/index.ts diff --git a/web/platform/src/modules/agent-bot/module.ts b/web-apps/platform/src/modules/agent-bot/module.ts similarity index 100% rename from web/platform/src/modules/agent-bot/module.ts rename to web-apps/platform/src/modules/agent-bot/module.ts diff --git a/web/platform/src/modules/agent-bot/protocol.ts b/web-apps/platform/src/modules/agent-bot/protocol.ts similarity index 100% rename from web/platform/src/modules/agent-bot/protocol.ts rename to web-apps/platform/src/modules/agent-bot/protocol.ts diff --git a/web/platform/src/modules/agent-module.ts b/web-apps/platform/src/modules/agent-module.ts similarity index 100% rename from web/platform/src/modules/agent-module.ts rename to web-apps/platform/src/modules/agent-module.ts diff --git a/web/platform/src/modules/app.module.ts b/web-apps/platform/src/modules/app.module.ts similarity index 100% rename from web/platform/src/modules/app.module.ts rename to web-apps/platform/src/modules/app.module.ts diff --git a/web/platform/src/modules/axios-client/client.ts b/web-apps/platform/src/modules/axios-client/client.ts similarity index 100% rename from web/platform/src/modules/axios-client/client.ts rename to web-apps/platform/src/modules/axios-client/client.ts diff --git a/web/platform/src/modules/axios-client/index.ts b/web-apps/platform/src/modules/axios-client/index.ts similarity index 100% rename from web/platform/src/modules/axios-client/index.ts rename to web-apps/platform/src/modules/axios-client/index.ts diff --git a/web/platform/src/modules/axios-client/module.ts b/web-apps/platform/src/modules/axios-client/module.ts similarity index 100% rename from web/platform/src/modules/axios-client/module.ts rename to web-apps/platform/src/modules/axios-client/module.ts diff --git a/web/platform/src/modules/axios-client/protocol.ts b/web-apps/platform/src/modules/axios-client/protocol.ts similarity index 100% rename from web/platform/src/modules/axios-client/protocol.ts rename to web-apps/platform/src/modules/axios-client/protocol.ts diff --git a/web/platform/src/modules/chat/chat-message.ts b/web-apps/platform/src/modules/chat/chat-message.ts similarity index 100% rename from web/platform/src/modules/chat/chat-message.ts rename to web-apps/platform/src/modules/chat/chat-message.ts diff --git a/web/platform/src/modules/chat/chat-turn.ts b/web-apps/platform/src/modules/chat/chat-turn.ts similarity index 100% rename from web/platform/src/modules/chat/chat-turn.ts rename to web-apps/platform/src/modules/chat/chat-turn.ts diff --git a/web/platform/src/modules/chat/chat.ts b/web-apps/platform/src/modules/chat/chat.ts similarity index 100% rename from web/platform/src/modules/chat/chat.ts rename to web-apps/platform/src/modules/chat/chat.ts diff --git a/web/platform/src/modules/chat/components/chat.tsx b/web-apps/platform/src/modules/chat/components/chat.tsx similarity index 100% rename from web/platform/src/modules/chat/components/chat.tsx rename to web-apps/platform/src/modules/chat/components/chat.tsx diff --git a/web/platform/src/modules/chat/components/index.less b/web-apps/platform/src/modules/chat/components/index.less similarity index 100% rename from web/platform/src/modules/chat/components/index.less rename to web-apps/platform/src/modules/chat/components/index.less diff --git a/web/platform/src/modules/chat/components/input/icon.tsx b/web-apps/platform/src/modules/chat/components/input/icon.tsx similarity index 100% rename from web/platform/src/modules/chat/components/input/icon.tsx rename to web-apps/platform/src/modules/chat/components/input/icon.tsx diff --git a/web/platform/src/modules/chat/components/input/index.less b/web-apps/platform/src/modules/chat/components/input/index.less similarity index 100% rename from web/platform/src/modules/chat/components/input/index.less rename to web-apps/platform/src/modules/chat/components/input/index.less diff --git a/web/platform/src/modules/chat/components/input/index.tsx b/web-apps/platform/src/modules/chat/components/input/index.tsx similarity index 100% rename from web/platform/src/modules/chat/components/input/index.tsx rename to web-apps/platform/src/modules/chat/components/input/index.tsx diff --git a/web/platform/src/modules/chat/components/message/group.tsx b/web-apps/platform/src/modules/chat/components/message/group.tsx similarity index 100% rename from web/platform/src/modules/chat/components/message/group.tsx rename to web-apps/platform/src/modules/chat/components/message/group.tsx diff --git a/web/platform/src/modules/chat/components/message/index.less b/web-apps/platform/src/modules/chat/components/message/index.less similarity index 100% rename from web/platform/src/modules/chat/components/message/index.less rename to web-apps/platform/src/modules/chat/components/message/index.less diff --git a/web/platform/src/modules/chat/components/message/markdown-message/index.less b/web-apps/platform/src/modules/chat/components/message/markdown-message/index.less similarity index 100% rename from web/platform/src/modules/chat/components/message/markdown-message/index.less rename to web-apps/platform/src/modules/chat/components/message/markdown-message/index.less diff --git a/web/platform/src/modules/chat/components/message/markdown-message/index.tsx b/web-apps/platform/src/modules/chat/components/message/markdown-message/index.tsx similarity index 100% rename from web/platform/src/modules/chat/components/message/markdown-message/index.tsx rename to web-apps/platform/src/modules/chat/components/message/markdown-message/index.tsx diff --git a/web/platform/src/modules/chat/components/message/markdown/index.less b/web-apps/platform/src/modules/chat/components/message/markdown/index.less similarity index 100% rename from web/platform/src/modules/chat/components/message/markdown/index.less rename to web-apps/platform/src/modules/chat/components/message/markdown/index.less diff --git a/web/platform/src/modules/chat/components/message/markdown/index.tsx b/web-apps/platform/src/modules/chat/components/message/markdown/index.tsx similarity index 100% rename from web/platform/src/modules/chat/components/message/markdown/index.tsx rename to web-apps/platform/src/modules/chat/components/message/markdown/index.tsx diff --git a/web/platform/src/modules/chat/components/message/markdown/modules/CodeBlock/index.less b/web-apps/platform/src/modules/chat/components/message/markdown/modules/CodeBlock/index.less similarity index 100% rename from web/platform/src/modules/chat/components/message/markdown/modules/CodeBlock/index.less rename to web-apps/platform/src/modules/chat/components/message/markdown/modules/CodeBlock/index.less diff --git a/web/platform/src/modules/chat/components/message/markdown/modules/CodeBlock/index.tsx b/web-apps/platform/src/modules/chat/components/message/markdown/modules/CodeBlock/index.tsx similarity index 100% rename from web/platform/src/modules/chat/components/message/markdown/modules/CodeBlock/index.tsx rename to web-apps/platform/src/modules/chat/components/message/markdown/modules/CodeBlock/index.tsx diff --git a/web/platform/src/modules/chat/components/message/message.tsx b/web-apps/platform/src/modules/chat/components/message/message.tsx similarity index 100% rename from web/platform/src/modules/chat/components/message/message.tsx rename to web-apps/platform/src/modules/chat/components/message/message.tsx diff --git a/web/platform/src/modules/chat/components/message/text/index.less b/web-apps/platform/src/modules/chat/components/message/text/index.less similarity index 100% rename from web/platform/src/modules/chat/components/message/text/index.less rename to web-apps/platform/src/modules/chat/components/message/text/index.less diff --git a/web/platform/src/modules/chat/components/message/text/index.tsx b/web-apps/platform/src/modules/chat/components/message/text/index.tsx similarity index 100% rename from web/platform/src/modules/chat/components/message/text/index.tsx rename to web-apps/platform/src/modules/chat/components/message/text/index.tsx diff --git a/web/platform/src/modules/chat/components/typing/index.less b/web-apps/platform/src/modules/chat/components/typing/index.less similarity index 100% rename from web/platform/src/modules/chat/components/typing/index.less rename to web-apps/platform/src/modules/chat/components/typing/index.less diff --git a/web/platform/src/modules/chat/components/typing/index.tsx b/web-apps/platform/src/modules/chat/components/typing/index.tsx similarity index 100% rename from web/platform/src/modules/chat/components/typing/index.tsx rename to web-apps/platform/src/modules/chat/components/typing/index.tsx diff --git a/web/platform/src/modules/chat/index.ts b/web-apps/platform/src/modules/chat/index.ts similarity index 100% rename from web/platform/src/modules/chat/index.ts rename to web-apps/platform/src/modules/chat/index.ts diff --git a/web/platform/src/modules/chat/manager.ts b/web-apps/platform/src/modules/chat/manager.ts similarity index 100% rename from web/platform/src/modules/chat/manager.ts rename to web-apps/platform/src/modules/chat/manager.ts diff --git a/web/platform/src/modules/chat/message-manager.ts b/web-apps/platform/src/modules/chat/message-manager.ts similarity index 100% rename from web/platform/src/modules/chat/message-manager.ts rename to web-apps/platform/src/modules/chat/message-manager.ts diff --git a/web/platform/src/modules/chat/module.ts b/web-apps/platform/src/modules/chat/module.ts similarity index 100% rename from web/platform/src/modules/chat/module.ts rename to web-apps/platform/src/modules/chat/module.ts diff --git a/web/platform/src/modules/chat/protocol.ts b/web-apps/platform/src/modules/chat/protocol.ts similarity index 100% rename from web/platform/src/modules/chat/protocol.ts rename to web-apps/platform/src/modules/chat/protocol.ts diff --git a/web/platform/src/modules/model/built-in-model-meta.ts b/web-apps/platform/src/modules/model/built-in-model-meta.ts similarity index 100% rename from web/platform/src/modules/model/built-in-model-meta.ts rename to web-apps/platform/src/modules/model/built-in-model-meta.ts diff --git a/web/platform/src/modules/model/index.ts b/web-apps/platform/src/modules/model/index.ts similarity index 100% rename from web/platform/src/modules/model/index.ts rename to web-apps/platform/src/modules/model/index.ts diff --git a/web/platform/src/modules/model/model-manager.ts b/web-apps/platform/src/modules/model/model-manager.ts similarity index 100% rename from web/platform/src/modules/model/model-manager.ts rename to web-apps/platform/src/modules/model/model-manager.ts diff --git a/web/platform/src/modules/model/model.ts b/web-apps/platform/src/modules/model/model.ts similarity index 100% rename from web/platform/src/modules/model/model.ts rename to web-apps/platform/src/modules/model/model.ts diff --git a/web/platform/src/modules/model/module.ts b/web-apps/platform/src/modules/model/module.ts similarity index 100% rename from web/platform/src/modules/model/module.ts rename to web-apps/platform/src/modules/model/module.ts diff --git a/web/platform/src/modules/model/protocol.ts b/web-apps/platform/src/modules/model/protocol.ts similarity index 100% rename from web/platform/src/modules/model/protocol.ts rename to web-apps/platform/src/modules/model/protocol.ts diff --git a/web/platform/src/modules/plugin/index.ts b/web-apps/platform/src/modules/plugin/index.ts similarity index 100% rename from web/platform/src/modules/plugin/index.ts rename to web-apps/platform/src/modules/plugin/index.ts diff --git a/web/platform/src/modules/plugin/module.ts b/web-apps/platform/src/modules/plugin/module.ts similarity index 100% rename from web/platform/src/modules/plugin/module.ts rename to web-apps/platform/src/modules/plugin/module.ts diff --git a/web/platform/src/modules/plugin/plugin-config-manager.ts b/web-apps/platform/src/modules/plugin/plugin-config-manager.ts similarity index 100% rename from web/platform/src/modules/plugin/plugin-config-manager.ts rename to web-apps/platform/src/modules/plugin/plugin-config-manager.ts diff --git a/web/platform/src/modules/plugin/plugin-config.ts b/web-apps/platform/src/modules/plugin/plugin-config.ts similarity index 100% rename from web/platform/src/modules/plugin/plugin-config.ts rename to web-apps/platform/src/modules/plugin/plugin-config.ts diff --git a/web/platform/src/modules/plugin/plugin-manager.ts b/web-apps/platform/src/modules/plugin/plugin-manager.ts similarity index 100% rename from web/platform/src/modules/plugin/plugin-manager.ts rename to web-apps/platform/src/modules/plugin/plugin-manager.ts diff --git a/web/platform/src/modules/plugin/plugin.ts b/web-apps/platform/src/modules/plugin/plugin.ts similarity index 100% rename from web/platform/src/modules/plugin/plugin.ts rename to web-apps/platform/src/modules/plugin/plugin.ts diff --git a/web/platform/src/modules/plugin/protocol.ts b/web-apps/platform/src/modules/plugin/protocol.ts similarity index 100% rename from web/platform/src/modules/plugin/protocol.ts rename to web-apps/platform/src/modules/plugin/protocol.ts diff --git a/web/platform/src/modules/user/components/user-avatar.tsx b/web-apps/platform/src/modules/user/components/user-avatar.tsx similarity index 100% rename from web/platform/src/modules/user/components/user-avatar.tsx rename to web-apps/platform/src/modules/user/components/user-avatar.tsx diff --git a/web/platform/src/modules/user/index.tsx b/web-apps/platform/src/modules/user/index.tsx similarity index 100% rename from web/platform/src/modules/user/index.tsx rename to web-apps/platform/src/modules/user/index.tsx diff --git a/web/platform/src/modules/user/module.ts b/web-apps/platform/src/modules/user/module.ts similarity index 100% rename from web/platform/src/modules/user/module.ts rename to web-apps/platform/src/modules/user/module.ts diff --git a/web/platform/src/modules/user/user-manager.ts b/web-apps/platform/src/modules/user/user-manager.ts similarity index 100% rename from web/platform/src/modules/user/user-manager.ts rename to web-apps/platform/src/modules/user/user-manager.ts diff --git a/web/platform/src/modules/user/user-protocol.ts b/web-apps/platform/src/modules/user/user-protocol.ts similarity index 100% rename from web/platform/src/modules/user/user-protocol.ts rename to web-apps/platform/src/modules/user/user-protocol.ts diff --git a/web/platform/src/modules/user/user.ts b/web-apps/platform/src/modules/user/user.ts similarity index 100% rename from web/platform/src/modules/user/user.ts rename to web-apps/platform/src/modules/user/user.ts diff --git a/web/platform/src/pages/bot/app.ts b/web-apps/platform/src/pages/bot/app.ts similarity index 100% rename from web/platform/src/pages/bot/app.ts rename to web-apps/platform/src/pages/bot/app.ts diff --git a/web/platform/src/pages/bot/avatar-view.tsx b/web-apps/platform/src/pages/bot/avatar-view.tsx similarity index 100% rename from web/platform/src/pages/bot/avatar-view.tsx rename to web-apps/platform/src/pages/bot/avatar-view.tsx diff --git a/web/platform/src/pages/bot/base-layout/index.less b/web-apps/platform/src/pages/bot/base-layout/index.less similarity index 100% rename from web/platform/src/pages/bot/base-layout/index.less rename to web-apps/platform/src/pages/bot/base-layout/index.less diff --git a/web/platform/src/pages/bot/base-layout/layout.tsx b/web-apps/platform/src/pages/bot/base-layout/layout.tsx similarity index 100% rename from web/platform/src/pages/bot/base-layout/layout.tsx rename to web-apps/platform/src/pages/bot/base-layout/layout.tsx diff --git a/web/platform/src/pages/bot/bot-config/index.less b/web-apps/platform/src/pages/bot/bot-config/index.less similarity index 100% rename from web/platform/src/pages/bot/bot-config/index.less rename to web-apps/platform/src/pages/bot/bot-config/index.less diff --git a/web/platform/src/pages/bot/bot-config/index.ts b/web-apps/platform/src/pages/bot/bot-config/index.ts similarity index 100% rename from web/platform/src/pages/bot/bot-config/index.ts rename to web-apps/platform/src/pages/bot/bot-config/index.ts diff --git a/web/platform/src/pages/bot/bot-config/view.tsx b/web-apps/platform/src/pages/bot/bot-config/view.tsx similarity index 100% rename from web/platform/src/pages/bot/bot-config/view.tsx rename to web-apps/platform/src/pages/bot/bot-config/view.tsx diff --git a/web/platform/src/pages/bot/bot-layout/index.less b/web-apps/platform/src/pages/bot/bot-layout/index.less similarity index 100% rename from web/platform/src/pages/bot/bot-layout/index.less rename to web-apps/platform/src/pages/bot/bot-layout/index.less diff --git a/web/platform/src/pages/bot/bot-layout/layout.tsx b/web-apps/platform/src/pages/bot/bot-layout/layout.tsx similarity index 100% rename from web/platform/src/pages/bot/bot-layout/layout.tsx rename to web-apps/platform/src/pages/bot/bot-layout/layout.tsx diff --git a/web/platform/src/pages/bot/bot-persona/index.less b/web-apps/platform/src/pages/bot/bot-persona/index.less similarity index 100% rename from web/platform/src/pages/bot/bot-persona/index.less rename to web-apps/platform/src/pages/bot/bot-persona/index.less diff --git a/web/platform/src/pages/bot/bot-persona/view.tsx b/web-apps/platform/src/pages/bot/bot-persona/view.tsx similarity index 100% rename from web/platform/src/pages/bot/bot-persona/view.tsx rename to web-apps/platform/src/pages/bot/bot-persona/view.tsx diff --git a/web/platform/src/pages/bot/bot-previewer/index.less b/web-apps/platform/src/pages/bot/bot-previewer/index.less similarity index 100% rename from web/platform/src/pages/bot/bot-previewer/index.less rename to web-apps/platform/src/pages/bot/bot-previewer/index.less diff --git a/web/platform/src/pages/bot/bot-previewer/index.ts b/web-apps/platform/src/pages/bot/bot-previewer/index.ts similarity index 100% rename from web/platform/src/pages/bot/bot-previewer/index.ts rename to web-apps/platform/src/pages/bot/bot-previewer/index.ts diff --git a/web/platform/src/pages/bot/bot-previewer/view.tsx b/web-apps/platform/src/pages/bot/bot-previewer/view.tsx similarity index 100% rename from web/platform/src/pages/bot/bot-previewer/view.tsx rename to web-apps/platform/src/pages/bot/bot-previewer/view.tsx diff --git a/web/platform/src/pages/bot/bot-provider.ts b/web-apps/platform/src/pages/bot/bot-provider.ts similarity index 100% rename from web/platform/src/pages/bot/bot-provider.ts rename to web-apps/platform/src/pages/bot/bot-provider.ts diff --git a/web/platform/src/pages/bot/bot-setting/index.less b/web-apps/platform/src/pages/bot/bot-setting/index.less similarity index 100% rename from web/platform/src/pages/bot/bot-setting/index.less rename to web-apps/platform/src/pages/bot/bot-setting/index.less diff --git a/web/platform/src/pages/bot/bot-setting/index.ts b/web-apps/platform/src/pages/bot/bot-setting/index.ts similarity index 100% rename from web/platform/src/pages/bot/bot-setting/index.ts rename to web-apps/platform/src/pages/bot/bot-setting/index.ts diff --git a/web/platform/src/pages/bot/bot-setting/view.tsx b/web-apps/platform/src/pages/bot/bot-setting/view.tsx similarity index 100% rename from web/platform/src/pages/bot/bot-setting/view.tsx rename to web-apps/platform/src/pages/bot/bot-setting/view.tsx diff --git a/web/platform/src/pages/bot/brand/index.less b/web-apps/platform/src/pages/bot/brand/index.less similarity index 100% rename from web/platform/src/pages/bot/brand/index.less rename to web-apps/platform/src/pages/bot/brand/index.less diff --git a/web/platform/src/pages/bot/brand/logo.svg b/web-apps/platform/src/pages/bot/brand/logo.svg similarity index 100% rename from web/platform/src/pages/bot/brand/logo.svg rename to web-apps/platform/src/pages/bot/brand/logo.svg diff --git a/web/platform/src/pages/bot/brand/logo.tsx b/web-apps/platform/src/pages/bot/brand/logo.tsx similarity index 100% rename from web/platform/src/pages/bot/brand/logo.tsx rename to web-apps/platform/src/pages/bot/brand/logo.tsx diff --git a/web/platform/src/pages/bot/brand/view.tsx b/web-apps/platform/src/pages/bot/brand/view.tsx similarity index 100% rename from web/platform/src/pages/bot/brand/view.tsx rename to web-apps/platform/src/pages/bot/brand/view.tsx diff --git a/web/platform/src/pages/bot/index.tsx b/web-apps/platform/src/pages/bot/index.tsx similarity index 100% rename from web/platform/src/pages/bot/index.tsx rename to web-apps/platform/src/pages/bot/index.tsx diff --git a/web/platform/src/pages/bot/model-selector/index.less b/web-apps/platform/src/pages/bot/model-selector/index.less similarity index 100% rename from web/platform/src/pages/bot/model-selector/index.less rename to web-apps/platform/src/pages/bot/model-selector/index.less diff --git a/web/platform/src/pages/bot/model-selector/view.tsx b/web-apps/platform/src/pages/bot/model-selector/view.tsx similarity index 100% rename from web/platform/src/pages/bot/model-selector/view.tsx rename to web-apps/platform/src/pages/bot/model-selector/view.tsx diff --git a/web/platform/src/pages/bot/module.ts b/web-apps/platform/src/pages/bot/module.ts similarity index 100% rename from web/platform/src/pages/bot/module.ts rename to web-apps/platform/src/pages/bot/module.ts diff --git a/web/platform/tsconfig.json b/web-apps/platform/tsconfig.json similarity index 100% rename from web/platform/tsconfig.json rename to web-apps/platform/tsconfig.json diff --git a/web/platform/typings.d.ts b/web-apps/platform/typings.d.ts similarity index 100% rename from web/platform/typings.d.ts rename to web-apps/platform/typings.d.ts diff --git a/web/platform/typings/index.d.ts b/web-apps/platform/typings/index.d.ts similarity index 100% rename from web/platform/typings/index.d.ts rename to web-apps/platform/typings/index.d.ts diff --git a/web/platform/umi-plugin-router.ts b/web-apps/platform/umi-plugin-router.ts similarity index 100% rename from web/platform/umi-plugin-router.ts rename to web-apps/platform/umi-plugin-router.ts diff --git a/web/ui/.editorconfig b/web-apps/ui/.editorconfig similarity index 100% rename from web/ui/.editorconfig rename to web-apps/ui/.editorconfig diff --git a/web/ui/.eslintignore b/web-apps/ui/.eslintignore similarity index 100% rename from web/ui/.eslintignore rename to web-apps/ui/.eslintignore diff --git a/web/ui/.eslintrc.json b/web-apps/ui/.eslintrc.json similarity index 100% rename from web/ui/.eslintrc.json rename to web-apps/ui/.eslintrc.json diff --git a/web/ui/.eslintrc.mjs b/web-apps/ui/.eslintrc.mjs similarity index 100% rename from web/ui/.eslintrc.mjs rename to web-apps/ui/.eslintrc.mjs diff --git a/web/ui/.gitignore b/web-apps/ui/.gitignore similarity index 100% rename from web/ui/.gitignore rename to web-apps/ui/.gitignore diff --git a/web/ui/.prettierignore b/web-apps/ui/.prettierignore similarity index 100% rename from web/ui/.prettierignore rename to web-apps/ui/.prettierignore diff --git a/web/ui/.prettierrc.json b/web-apps/ui/.prettierrc.json similarity index 100% rename from web/ui/.prettierrc.json rename to web-apps/ui/.prettierrc.json diff --git a/web/ui/.stylelintignore b/web-apps/ui/.stylelintignore similarity index 100% rename from web/ui/.stylelintignore rename to web-apps/ui/.stylelintignore diff --git a/web/ui/.stylelintrc b/web-apps/ui/.stylelintrc similarity index 100% rename from web/ui/.stylelintrc rename to web-apps/ui/.stylelintrc diff --git a/web/ui/README.md b/web-apps/ui/README.md similarity index 100% rename from web/ui/README.md rename to web-apps/ui/README.md diff --git a/web/ui/config/config.ts b/web-apps/ui/config/config.ts similarity index 100% rename from web/ui/config/config.ts rename to web-apps/ui/config/config.ts diff --git a/web/ui/config/dumi-plugin-nodenext.ts b/web-apps/ui/config/dumi-plugin-nodenext.ts similarity index 100% rename from web/ui/config/dumi-plugin-nodenext.ts rename to web-apps/ui/config/dumi-plugin-nodenext.ts diff --git a/web/ui/config/routes.ts b/web-apps/ui/config/routes.ts similarity index 100% rename from web/ui/config/routes.ts rename to web-apps/ui/config/routes.ts diff --git a/web/ui/config/umi-plugin-mana.ts b/web-apps/ui/config/umi-plugin-mana.ts similarity index 100% rename from web/ui/config/umi-plugin-mana.ts rename to web-apps/ui/config/umi-plugin-mana.ts diff --git a/web/ui/config/umi-plugin-router.ts b/web-apps/ui/config/umi-plugin-router.ts similarity index 100% rename from web/ui/config/umi-plugin-router.ts rename to web-apps/ui/config/umi-plugin-router.ts diff --git a/web/ui/package.json b/web-apps/ui/package.json similarity index 100% rename from web/ui/package.json rename to web-apps/ui/package.json diff --git a/web/ui/public/favicon.ico b/web-apps/ui/public/favicon.ico similarity index 100% rename from web/ui/public/favicon.ico rename to web-apps/ui/public/favicon.ico diff --git a/web/ui/src/app.ts b/web-apps/ui/src/app.ts similarity index 100% rename from web/ui/src/app.ts rename to web-apps/ui/src/app.ts diff --git a/web/ui/src/common/async-model.ts b/web-apps/ui/src/common/async-model.ts similarity index 100% rename from web/ui/src/common/async-model.ts rename to web-apps/ui/src/common/async-model.ts diff --git a/web/ui/src/common/page-config.ts b/web-apps/ui/src/common/page-config.ts similarity index 100% rename from web/ui/src/common/page-config.ts rename to web-apps/ui/src/common/page-config.ts diff --git a/web/ui/src/common/utils.ts b/web-apps/ui/src/common/utils.ts similarity index 100% rename from web/ui/src/common/utils.ts rename to web-apps/ui/src/common/utils.ts diff --git a/web/ui/src/components/avatar-upload/index.less b/web-apps/ui/src/components/avatar-upload/index.less similarity index 100% rename from web/ui/src/components/avatar-upload/index.less rename to web-apps/ui/src/components/avatar-upload/index.less diff --git a/web/ui/src/components/avatar-upload/index.tsx b/web-apps/ui/src/components/avatar-upload/index.tsx similarity index 100% rename from web/ui/src/components/avatar-upload/index.tsx rename to web-apps/ui/src/components/avatar-upload/index.tsx diff --git a/web/ui/src/constant/default.ts b/web-apps/ui/src/constant/default.ts similarity index 100% rename from web/ui/src/constant/default.ts rename to web-apps/ui/src/constant/default.ts diff --git a/web/ui/src/modules/agent/agent-config-manager.ts b/web-apps/ui/src/modules/agent/agent-config-manager.ts similarity index 100% rename from web/ui/src/modules/agent/agent-config-manager.ts rename to web-apps/ui/src/modules/agent/agent-config-manager.ts diff --git a/web/ui/src/modules/agent/agent-config.ts b/web-apps/ui/src/modules/agent/agent-config.ts similarity index 100% rename from web/ui/src/modules/agent/agent-config.ts rename to web-apps/ui/src/modules/agent/agent-config.ts diff --git a/web/ui/src/modules/agent/agent-icon.tsx b/web-apps/ui/src/modules/agent/agent-icon.tsx similarity index 100% rename from web/ui/src/modules/agent/agent-icon.tsx rename to web-apps/ui/src/modules/agent/agent-icon.tsx diff --git a/web/ui/src/modules/agent/agent-manager.ts b/web-apps/ui/src/modules/agent/agent-manager.ts similarity index 100% rename from web/ui/src/modules/agent/agent-manager.ts rename to web-apps/ui/src/modules/agent/agent-manager.ts diff --git a/web/ui/src/modules/agent/agent-market.ts b/web-apps/ui/src/modules/agent/agent-market.ts similarity index 100% rename from web/ui/src/modules/agent/agent-market.ts rename to web-apps/ui/src/modules/agent/agent-market.ts diff --git a/web/ui/src/modules/agent/agent-model.ts b/web-apps/ui/src/modules/agent/agent-model.ts similarity index 100% rename from web/ui/src/modules/agent/agent-model.ts rename to web-apps/ui/src/modules/agent/agent-model.ts diff --git a/web/ui/src/modules/agent/module.ts b/web-apps/ui/src/modules/agent/module.ts similarity index 100% rename from web/ui/src/modules/agent/module.ts rename to web-apps/ui/src/modules/agent/module.ts diff --git a/web/ui/src/modules/agent/protocol.ts b/web-apps/ui/src/modules/agent/protocol.ts similarity index 100% rename from web/ui/src/modules/agent/protocol.ts rename to web-apps/ui/src/modules/agent/protocol.ts diff --git a/web/ui/src/modules/app.module.ts b/web-apps/ui/src/modules/app.module.ts similarity index 100% rename from web/ui/src/modules/app.module.ts rename to web-apps/ui/src/modules/app.module.ts diff --git a/web/ui/src/modules/axios-client/client.ts b/web-apps/ui/src/modules/axios-client/client.ts similarity index 100% rename from web/ui/src/modules/axios-client/client.ts rename to web-apps/ui/src/modules/axios-client/client.ts diff --git a/web/ui/src/modules/axios-client/module.ts b/web-apps/ui/src/modules/axios-client/module.ts similarity index 100% rename from web/ui/src/modules/axios-client/module.ts rename to web-apps/ui/src/modules/axios-client/module.ts diff --git a/web/ui/src/modules/axios-client/protocol.ts b/web-apps/ui/src/modules/axios-client/protocol.ts similarity index 100% rename from web/ui/src/modules/axios-client/protocol.ts rename to web-apps/ui/src/modules/axios-client/protocol.ts diff --git a/web/ui/src/modules/base-layout/back/index.less b/web-apps/ui/src/modules/base-layout/back/index.less similarity index 100% rename from web/ui/src/modules/base-layout/back/index.less rename to web-apps/ui/src/modules/base-layout/back/index.less diff --git a/web/ui/src/modules/base-layout/back/view.tsx b/web-apps/ui/src/modules/base-layout/back/view.tsx similarity index 100% rename from web/ui/src/modules/base-layout/back/view.tsx rename to web-apps/ui/src/modules/base-layout/back/view.tsx diff --git a/web/ui/src/modules/base-layout/brand/brand.jpg b/web-apps/ui/src/modules/base-layout/brand/brand.jpg similarity index 100% rename from web/ui/src/modules/base-layout/brand/brand.jpg rename to web-apps/ui/src/modules/base-layout/brand/brand.jpg diff --git a/web/ui/src/modules/base-layout/brand/index.less b/web-apps/ui/src/modules/base-layout/brand/index.less similarity index 100% rename from web/ui/src/modules/base-layout/brand/index.less rename to web-apps/ui/src/modules/base-layout/brand/index.less diff --git a/web/ui/src/modules/base-layout/brand/logo.tsx b/web-apps/ui/src/modules/base-layout/brand/logo.tsx similarity index 100% rename from web/ui/src/modules/base-layout/brand/logo.tsx rename to web-apps/ui/src/modules/base-layout/brand/logo.tsx diff --git a/web/ui/src/modules/base-layout/brand/view.tsx b/web-apps/ui/src/modules/base-layout/brand/view.tsx similarity index 100% rename from web/ui/src/modules/base-layout/brand/view.tsx rename to web-apps/ui/src/modules/base-layout/brand/view.tsx diff --git a/web/ui/src/modules/base-layout/github/view.tsx b/web-apps/ui/src/modules/base-layout/github/view.tsx similarity index 100% rename from web/ui/src/modules/base-layout/github/view.tsx rename to web-apps/ui/src/modules/base-layout/github/view.tsx diff --git a/web/ui/src/modules/base-layout/index.less b/web-apps/ui/src/modules/base-layout/index.less similarity index 100% rename from web/ui/src/modules/base-layout/index.less rename to web-apps/ui/src/modules/base-layout/index.less diff --git a/web/ui/src/modules/base-layout/layout.tsx b/web-apps/ui/src/modules/base-layout/layout.tsx similarity index 100% rename from web/ui/src/modules/base-layout/layout.tsx rename to web-apps/ui/src/modules/base-layout/layout.tsx diff --git a/web/ui/src/modules/base-layout/main-view.ts b/web-apps/ui/src/modules/base-layout/main-view.ts similarity index 100% rename from web/ui/src/modules/base-layout/main-view.ts rename to web-apps/ui/src/modules/base-layout/main-view.ts diff --git a/web/ui/src/modules/base-layout/module.ts b/web-apps/ui/src/modules/base-layout/module.ts similarity index 100% rename from web/ui/src/modules/base-layout/module.ts rename to web-apps/ui/src/modules/base-layout/module.ts diff --git a/web/ui/src/modules/base-layout/page-view.tsx b/web-apps/ui/src/modules/base-layout/page-view.tsx similarity index 100% rename from web/ui/src/modules/base-layout/page-view.tsx rename to web-apps/ui/src/modules/base-layout/page-view.tsx diff --git a/web/ui/src/modules/base-layout/protocol.ts b/web-apps/ui/src/modules/base-layout/protocol.ts similarity index 100% rename from web/ui/src/modules/base-layout/protocol.ts rename to web-apps/ui/src/modules/base-layout/protocol.ts diff --git a/web/ui/src/modules/base-layout/title/index.less b/web-apps/ui/src/modules/base-layout/title/index.less similarity index 100% rename from web/ui/src/modules/base-layout/title/index.less rename to web-apps/ui/src/modules/base-layout/title/index.less diff --git a/web/ui/src/modules/base-layout/title/view.tsx b/web-apps/ui/src/modules/base-layout/title/view.tsx similarity index 100% rename from web/ui/src/modules/base-layout/title/view.tsx rename to web-apps/ui/src/modules/base-layout/title/view.tsx diff --git a/web/ui/src/modules/chat-message/ai-message-item.ts b/web-apps/ui/src/modules/chat-message/ai-message-item.ts similarity index 100% rename from web/ui/src/modules/chat-message/ai-message-item.ts rename to web-apps/ui/src/modules/chat-message/ai-message-item.ts diff --git a/web/ui/src/modules/chat-message/chat-message-item.ts b/web-apps/ui/src/modules/chat-message/chat-message-item.ts similarity index 100% rename from web/ui/src/modules/chat-message/chat-message-item.ts rename to web-apps/ui/src/modules/chat-message/chat-message-item.ts diff --git a/web/ui/src/modules/chat-message/chat-message-manager.ts b/web-apps/ui/src/modules/chat-message/chat-message-manager.ts similarity index 100% rename from web/ui/src/modules/chat-message/chat-message-manager.ts rename to web-apps/ui/src/modules/chat-message/chat-message-manager.ts diff --git a/web/ui/src/modules/chat-message/chat-message-model.ts b/web-apps/ui/src/modules/chat-message/chat-message-model.ts similarity index 100% rename from web/ui/src/modules/chat-message/chat-message-model.ts rename to web-apps/ui/src/modules/chat-message/chat-message-model.ts diff --git a/web/ui/src/modules/chat-message/module.ts b/web-apps/ui/src/modules/chat-message/module.ts similarity index 100% rename from web/ui/src/modules/chat-message/module.ts rename to web-apps/ui/src/modules/chat-message/module.ts diff --git a/web/ui/src/modules/chat-message/peer-message-item-model.ts b/web-apps/ui/src/modules/chat-message/peer-message-item-model.ts similarity index 100% rename from web/ui/src/modules/chat-message/peer-message-item-model.ts rename to web-apps/ui/src/modules/chat-message/peer-message-item-model.ts diff --git a/web/ui/src/modules/chat-message/protocol.ts b/web-apps/ui/src/modules/chat-message/protocol.ts similarity index 100% rename from web/ui/src/modules/chat-message/protocol.ts rename to web-apps/ui/src/modules/chat-message/protocol.ts diff --git a/web/ui/src/modules/knowledge/knowledge-icon.tsx b/web-apps/ui/src/modules/knowledge/knowledge-icon.tsx similarity index 100% rename from web/ui/src/modules/knowledge/knowledge-icon.tsx rename to web-apps/ui/src/modules/knowledge/knowledge-icon.tsx diff --git a/web/ui/src/modules/knowledge/knowledge-manager.ts b/web-apps/ui/src/modules/knowledge/knowledge-manager.ts similarity index 100% rename from web/ui/src/modules/knowledge/knowledge-manager.ts rename to web-apps/ui/src/modules/knowledge/knowledge-manager.ts diff --git a/web/ui/src/modules/knowledge/knowledge-model.ts b/web-apps/ui/src/modules/knowledge/knowledge-model.ts similarity index 100% rename from web/ui/src/modules/knowledge/knowledge-model.ts rename to web-apps/ui/src/modules/knowledge/knowledge-model.ts diff --git a/web/ui/src/modules/knowledge/knowledge-space.ts b/web-apps/ui/src/modules/knowledge/knowledge-space.ts similarity index 100% rename from web/ui/src/modules/knowledge/knowledge-space.ts rename to web-apps/ui/src/modules/knowledge/knowledge-space.ts diff --git a/web/ui/src/modules/knowledge/module.ts b/web-apps/ui/src/modules/knowledge/module.ts similarity index 100% rename from web/ui/src/modules/knowledge/module.ts rename to web-apps/ui/src/modules/knowledge/module.ts diff --git a/web/ui/src/modules/knowledge/protocol.ts b/web-apps/ui/src/modules/knowledge/protocol.ts similarity index 100% rename from web/ui/src/modules/knowledge/protocol.ts rename to web-apps/ui/src/modules/knowledge/protocol.ts diff --git a/web/ui/src/modules/model/index.ts b/web-apps/ui/src/modules/model/index.ts similarity index 100% rename from web/ui/src/modules/model/index.ts rename to web-apps/ui/src/modules/model/index.ts diff --git a/web/ui/src/modules/model/llm-manager.ts b/web-apps/ui/src/modules/model/llm-manager.ts similarity index 100% rename from web/ui/src/modules/model/llm-manager.ts rename to web-apps/ui/src/modules/model/llm-manager.ts diff --git a/web/ui/src/modules/model/llm-model.ts b/web-apps/ui/src/modules/model/llm-model.ts similarity index 100% rename from web/ui/src/modules/model/llm-model.ts rename to web-apps/ui/src/modules/model/llm-model.ts diff --git a/web/ui/src/modules/model/model-icon/baichuan.svg b/web-apps/ui/src/modules/model/model-icon/baichuan.svg similarity index 100% rename from web/ui/src/modules/model/model-icon/baichuan.svg rename to web-apps/ui/src/modules/model/model-icon/baichuan.svg diff --git a/web/ui/src/modules/model/model-icon/deepseek.svg b/web-apps/ui/src/modules/model/model-icon/deepseek.svg similarity index 100% rename from web/ui/src/modules/model/model-icon/deepseek.svg rename to web-apps/ui/src/modules/model/model-icon/deepseek.svg diff --git a/web/ui/src/modules/model/model-icon/ernie.svg b/web-apps/ui/src/modules/model/model-icon/ernie.svg similarity index 100% rename from web/ui/src/modules/model/model-icon/ernie.svg rename to web-apps/ui/src/modules/model/model-icon/ernie.svg diff --git a/web/ui/src/modules/model/model-icon/index.tsx b/web-apps/ui/src/modules/model/model-icon/index.tsx similarity index 100% rename from web/ui/src/modules/model/model-icon/index.tsx rename to web-apps/ui/src/modules/model/model-icon/index.tsx diff --git a/web/ui/src/modules/model/model-icon/moonshot.svg b/web-apps/ui/src/modules/model/model-icon/moonshot.svg similarity index 100% rename from web/ui/src/modules/model/model-icon/moonshot.svg rename to web-apps/ui/src/modules/model/model-icon/moonshot.svg diff --git a/web/ui/src/modules/model/model-icon/openai.svg b/web-apps/ui/src/modules/model/model-icon/openai.svg similarity index 100% rename from web/ui/src/modules/model/model-icon/openai.svg rename to web-apps/ui/src/modules/model/model-icon/openai.svg diff --git a/web/ui/src/modules/model/model-icon/qwen.svg b/web-apps/ui/src/modules/model/model-icon/qwen.svg similarity index 100% rename from web/ui/src/modules/model/model-icon/qwen.svg rename to web-apps/ui/src/modules/model/model-icon/qwen.svg diff --git a/web/ui/src/modules/model/module.ts b/web-apps/ui/src/modules/model/module.ts similarity index 100% rename from web/ui/src/modules/model/module.ts rename to web-apps/ui/src/modules/model/module.ts diff --git a/web/ui/src/modules/model/protocol.ts b/web-apps/ui/src/modules/model/protocol.ts similarity index 100% rename from web/ui/src/modules/model/protocol.ts rename to web-apps/ui/src/modules/model/protocol.ts diff --git a/web/ui/src/modules/session/module.ts b/web-apps/ui/src/modules/session/module.ts similarity index 100% rename from web/ui/src/modules/session/module.ts rename to web-apps/ui/src/modules/session/module.ts diff --git a/web/ui/src/modules/session/protocol.ts b/web-apps/ui/src/modules/session/protocol.ts similarity index 100% rename from web/ui/src/modules/session/protocol.ts rename to web-apps/ui/src/modules/session/protocol.ts diff --git a/web/ui/src/modules/session/session-manager.ts b/web-apps/ui/src/modules/session/session-manager.ts similarity index 100% rename from web/ui/src/modules/session/session-manager.ts rename to web-apps/ui/src/modules/session/session-manager.ts diff --git a/web/ui/src/modules/session/session-model.ts b/web-apps/ui/src/modules/session/session-model.ts similarity index 100% rename from web/ui/src/modules/session/session-model.ts rename to web-apps/ui/src/modules/session/session-model.ts diff --git a/web/ui/src/modules/tool/module.ts b/web-apps/ui/src/modules/tool/module.ts similarity index 100% rename from web/ui/src/modules/tool/module.ts rename to web-apps/ui/src/modules/tool/module.ts diff --git a/web/ui/src/modules/tool/protocol.ts b/web-apps/ui/src/modules/tool/protocol.ts similarity index 100% rename from web/ui/src/modules/tool/protocol.ts rename to web-apps/ui/src/modules/tool/protocol.ts diff --git a/web/ui/src/modules/tool/tool-config-manager.ts b/web-apps/ui/src/modules/tool/tool-config-manager.ts similarity index 100% rename from web/ui/src/modules/tool/tool-config-manager.ts rename to web-apps/ui/src/modules/tool/tool-config-manager.ts diff --git a/web/ui/src/modules/tool/tool-config.ts b/web-apps/ui/src/modules/tool/tool-config.ts similarity index 100% rename from web/ui/src/modules/tool/tool-config.ts rename to web-apps/ui/src/modules/tool/tool-config.ts diff --git a/web/ui/src/modules/tool/tool-icon.tsx b/web-apps/ui/src/modules/tool/tool-icon.tsx similarity index 100% rename from web/ui/src/modules/tool/tool-icon.tsx rename to web-apps/ui/src/modules/tool/tool-icon.tsx diff --git a/web/ui/src/modules/tool/tool-manager.ts b/web-apps/ui/src/modules/tool/tool-manager.ts similarity index 100% rename from web/ui/src/modules/tool/tool-manager.ts rename to web-apps/ui/src/modules/tool/tool-manager.ts diff --git a/web/ui/src/modules/tool/tool-model.ts b/web-apps/ui/src/modules/tool/tool-model.ts similarity index 100% rename from web/ui/src/modules/tool/tool-model.ts rename to web-apps/ui/src/modules/tool/tool-model.ts diff --git a/web/ui/src/modules/tool/tool-space.ts b/web-apps/ui/src/modules/tool/tool-space.ts similarity index 100% rename from web/ui/src/modules/tool/tool-space.ts rename to web-apps/ui/src/modules/tool/tool-space.ts diff --git a/web/ui/src/views/agent-config/components/character-setting/index.less b/web-apps/ui/src/views/agent-config/components/character-setting/index.less similarity index 100% rename from web/ui/src/views/agent-config/components/character-setting/index.less rename to web-apps/ui/src/views/agent-config/components/character-setting/index.less diff --git a/web/ui/src/views/agent-config/components/character-setting/index.tsx b/web-apps/ui/src/views/agent-config/components/character-setting/index.tsx similarity index 100% rename from web/ui/src/views/agent-config/components/character-setting/index.tsx rename to web-apps/ui/src/views/agent-config/components/character-setting/index.tsx diff --git a/web/ui/src/views/agent-config/components/character-setting/textarea.tsx b/web-apps/ui/src/views/agent-config/components/character-setting/textarea.tsx similarity index 100% rename from web/ui/src/views/agent-config/components/character-setting/textarea.tsx rename to web-apps/ui/src/views/agent-config/components/character-setting/textarea.tsx diff --git a/web/ui/src/views/agent-config/components/config-selector/index.less b/web-apps/ui/src/views/agent-config/components/config-selector/index.less similarity index 100% rename from web/ui/src/views/agent-config/components/config-selector/index.less rename to web-apps/ui/src/views/agent-config/components/config-selector/index.less diff --git a/web/ui/src/views/agent-config/components/config-selector/index.tsx b/web-apps/ui/src/views/agent-config/components/config-selector/index.tsx similarity index 100% rename from web/ui/src/views/agent-config/components/config-selector/index.tsx rename to web-apps/ui/src/views/agent-config/components/config-selector/index.tsx diff --git a/web/ui/src/views/agent-config/components/item-crad/index.less b/web-apps/ui/src/views/agent-config/components/item-crad/index.less similarity index 100% rename from web/ui/src/views/agent-config/components/item-crad/index.less rename to web-apps/ui/src/views/agent-config/components/item-crad/index.less diff --git a/web/ui/src/views/agent-config/components/item-crad/index.tsx b/web-apps/ui/src/views/agent-config/components/item-crad/index.tsx similarity index 100% rename from web/ui/src/views/agent-config/components/item-crad/index.tsx rename to web-apps/ui/src/views/agent-config/components/item-crad/index.tsx diff --git a/web/ui/src/views/agent-config/components/model-selector/index.less b/web-apps/ui/src/views/agent-config/components/model-selector/index.less similarity index 100% rename from web/ui/src/views/agent-config/components/model-selector/index.less rename to web-apps/ui/src/views/agent-config/components/model-selector/index.less diff --git a/web/ui/src/views/agent-config/components/model-selector/index.tsx b/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx similarity index 100% rename from web/ui/src/views/agent-config/components/model-selector/index.tsx rename to web-apps/ui/src/views/agent-config/components/model-selector/index.tsx diff --git a/web/ui/src/views/agent-config/index.less b/web-apps/ui/src/views/agent-config/index.less similarity index 100% rename from web/ui/src/views/agent-config/index.less rename to web-apps/ui/src/views/agent-config/index.less diff --git a/web/ui/src/views/agent-config/index.tsx b/web-apps/ui/src/views/agent-config/index.tsx similarity index 100% rename from web/ui/src/views/agent-config/index.tsx rename to web-apps/ui/src/views/agent-config/index.tsx diff --git a/web/ui/src/views/agent-config/knowledge-modal/index.ts b/web-apps/ui/src/views/agent-config/knowledge-modal/index.ts similarity index 100% rename from web/ui/src/views/agent-config/knowledge-modal/index.ts rename to web-apps/ui/src/views/agent-config/knowledge-modal/index.ts diff --git a/web/ui/src/views/agent-config/knowledge-modal/modal.tsx b/web-apps/ui/src/views/agent-config/knowledge-modal/modal.tsx similarity index 100% rename from web/ui/src/views/agent-config/knowledge-modal/modal.tsx rename to web-apps/ui/src/views/agent-config/knowledge-modal/modal.tsx diff --git a/web/ui/src/views/agent-config/module.ts b/web-apps/ui/src/views/agent-config/module.ts similarity index 100% rename from web/ui/src/views/agent-config/module.ts rename to web-apps/ui/src/views/agent-config/module.ts diff --git a/web/ui/src/views/agent-config/protocol.ts b/web-apps/ui/src/views/agent-config/protocol.ts similarity index 100% rename from web/ui/src/views/agent-config/protocol.ts rename to web-apps/ui/src/views/agent-config/protocol.ts diff --git a/web/ui/src/views/agent-config/tools-modal/index.ts b/web-apps/ui/src/views/agent-config/tools-modal/index.ts similarity index 100% rename from web/ui/src/views/agent-config/tools-modal/index.ts rename to web-apps/ui/src/views/agent-config/tools-modal/index.ts diff --git a/web/ui/src/views/agent-config/tools-modal/modal.tsx b/web-apps/ui/src/views/agent-config/tools-modal/modal.tsx similarity index 100% rename from web/ui/src/views/agent-config/tools-modal/modal.tsx rename to web-apps/ui/src/views/agent-config/tools-modal/modal.tsx diff --git a/web/ui/src/views/agent-config/view.tsx b/web-apps/ui/src/views/agent-config/view.tsx similarity index 100% rename from web/ui/src/views/agent-config/view.tsx rename to web-apps/ui/src/views/agent-config/view.tsx diff --git a/web/ui/src/views/agent-dev/chat-view.tsx b/web-apps/ui/src/views/agent-dev/chat-view.tsx similarity index 100% rename from web/ui/src/views/agent-dev/chat-view.tsx rename to web-apps/ui/src/views/agent-dev/chat-view.tsx diff --git a/web/ui/src/views/agent-dev/dev-view.tsx b/web-apps/ui/src/views/agent-dev/dev-view.tsx similarity index 100% rename from web/ui/src/views/agent-dev/dev-view.tsx rename to web-apps/ui/src/views/agent-dev/dev-view.tsx diff --git a/web/ui/src/views/agent-dev/index.less b/web-apps/ui/src/views/agent-dev/index.less similarity index 100% rename from web/ui/src/views/agent-dev/index.less rename to web-apps/ui/src/views/agent-dev/index.less diff --git a/web/ui/src/views/agent-dev/index.tsx b/web-apps/ui/src/views/agent-dev/index.tsx similarity index 100% rename from web/ui/src/views/agent-dev/index.tsx rename to web-apps/ui/src/views/agent-dev/index.tsx diff --git a/web/ui/src/views/agent-dev/module.ts b/web-apps/ui/src/views/agent-dev/module.ts similarity index 100% rename from web/ui/src/views/agent-dev/module.ts rename to web-apps/ui/src/views/agent-dev/module.ts diff --git a/web/ui/src/views/agent-dev/protocol.ts b/web-apps/ui/src/views/agent-dev/protocol.ts similarity index 100% rename from web/ui/src/views/agent-dev/protocol.ts rename to web-apps/ui/src/views/agent-dev/protocol.ts diff --git a/web/ui/src/views/agent-flow/agent-flow-view.tsx b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx similarity index 100% rename from web/ui/src/views/agent-flow/agent-flow-view.tsx rename to web-apps/ui/src/views/agent-flow/agent-flow-view.tsx diff --git a/web/ui/src/views/agent-flow/flow-dev-view.tsx b/web-apps/ui/src/views/agent-flow/flow-dev-view.tsx similarity index 100% rename from web/ui/src/views/agent-flow/flow-dev-view.tsx rename to web-apps/ui/src/views/agent-flow/flow-dev-view.tsx diff --git a/web/ui/src/views/agent-flow/index.less b/web-apps/ui/src/views/agent-flow/index.less similarity index 100% rename from web/ui/src/views/agent-flow/index.less rename to web-apps/ui/src/views/agent-flow/index.less diff --git a/web/ui/src/views/agent-flow/index.tsx b/web-apps/ui/src/views/agent-flow/index.tsx similarity index 100% rename from web/ui/src/views/agent-flow/index.tsx rename to web-apps/ui/src/views/agent-flow/index.tsx diff --git a/web/ui/src/views/agent-flow/module.ts b/web-apps/ui/src/views/agent-flow/module.ts similarity index 100% rename from web/ui/src/views/agent-flow/module.ts rename to web-apps/ui/src/views/agent-flow/module.ts diff --git a/web/ui/src/views/agent-flow/protocol.ts b/web-apps/ui/src/views/agent-flow/protocol.ts similarity index 100% rename from web/ui/src/views/agent-flow/protocol.ts rename to web-apps/ui/src/views/agent-flow/protocol.ts diff --git a/web/ui/src/views/agent-flow/utils.ts b/web-apps/ui/src/views/agent-flow/utils.ts similarity index 100% rename from web/ui/src/views/agent-flow/utils.ts rename to web-apps/ui/src/views/agent-flow/utils.ts diff --git a/web/ui/src/views/agents/index.less b/web-apps/ui/src/views/agents/index.less similarity index 100% rename from web/ui/src/views/agents/index.less rename to web-apps/ui/src/views/agents/index.less diff --git a/web/ui/src/views/agents/index.tsx b/web-apps/ui/src/views/agents/index.tsx similarity index 100% rename from web/ui/src/views/agents/index.tsx rename to web-apps/ui/src/views/agents/index.tsx diff --git a/web/ui/src/views/agents/modal/contribution.ts b/web-apps/ui/src/views/agents/modal/contribution.ts similarity index 100% rename from web/ui/src/views/agents/modal/contribution.ts rename to web-apps/ui/src/views/agents/modal/contribution.ts diff --git a/web/ui/src/views/agents/modal/create.tsx b/web-apps/ui/src/views/agents/modal/create.tsx similarity index 100% rename from web/ui/src/views/agents/modal/create.tsx rename to web-apps/ui/src/views/agents/modal/create.tsx diff --git a/web/ui/src/views/agents/modal/index.less b/web-apps/ui/src/views/agents/modal/index.less similarity index 100% rename from web/ui/src/views/agents/modal/index.less rename to web-apps/ui/src/views/agents/modal/index.less diff --git a/web/ui/src/views/agents/module.ts b/web-apps/ui/src/views/agents/module.ts similarity index 100% rename from web/ui/src/views/agents/module.ts rename to web-apps/ui/src/views/agents/module.ts diff --git a/web/ui/src/views/agents/view.tsx b/web-apps/ui/src/views/agents/view.tsx similarity index 100% rename from web/ui/src/views/agents/view.tsx rename to web-apps/ui/src/views/agents/view.tsx diff --git a/web/ui/src/views/chat/components/input/icon.tsx b/web-apps/ui/src/views/chat/components/input/icon.tsx similarity index 100% rename from web/ui/src/views/chat/components/input/icon.tsx rename to web-apps/ui/src/views/chat/components/input/icon.tsx diff --git a/web/ui/src/views/chat/components/input/index.less b/web-apps/ui/src/views/chat/components/input/index.less similarity index 100% rename from web/ui/src/views/chat/components/input/index.less rename to web-apps/ui/src/views/chat/components/input/index.less diff --git a/web/ui/src/views/chat/components/input/index.tsx b/web-apps/ui/src/views/chat/components/input/index.tsx similarity index 100% rename from web/ui/src/views/chat/components/input/index.tsx rename to web-apps/ui/src/views/chat/components/input/index.tsx diff --git a/web/ui/src/views/chat/components/message/ai-message.tsx b/web-apps/ui/src/views/chat/components/message/ai-message.tsx similarity index 100% rename from web/ui/src/views/chat/components/message/ai-message.tsx rename to web-apps/ui/src/views/chat/components/message/ai-message.tsx diff --git a/web/ui/src/views/chat/components/message/exchange.tsx b/web-apps/ui/src/views/chat/components/message/exchange.tsx similarity index 100% rename from web/ui/src/views/chat/components/message/exchange.tsx rename to web-apps/ui/src/views/chat/components/message/exchange.tsx diff --git a/web/ui/src/views/chat/components/message/human-message.tsx b/web-apps/ui/src/views/chat/components/message/human-message.tsx similarity index 100% rename from web/ui/src/views/chat/components/message/human-message.tsx rename to web-apps/ui/src/views/chat/components/message/human-message.tsx diff --git a/web/ui/src/views/chat/components/message/index.less b/web-apps/ui/src/views/chat/components/message/index.less similarity index 100% rename from web/ui/src/views/chat/components/message/index.less rename to web-apps/ui/src/views/chat/components/message/index.less diff --git a/web/ui/src/views/chat/components/message/markdown/index.less b/web-apps/ui/src/views/chat/components/message/markdown/index.less similarity index 100% rename from web/ui/src/views/chat/components/message/markdown/index.less rename to web-apps/ui/src/views/chat/components/message/markdown/index.less diff --git a/web/ui/src/views/chat/components/message/markdown/index.tsx b/web-apps/ui/src/views/chat/components/message/markdown/index.tsx similarity index 100% rename from web/ui/src/views/chat/components/message/markdown/index.tsx rename to web-apps/ui/src/views/chat/components/message/markdown/index.tsx diff --git a/web/ui/src/views/chat/components/message/markdown/modules/CodeBlock/index.less b/web-apps/ui/src/views/chat/components/message/markdown/modules/CodeBlock/index.less similarity index 100% rename from web/ui/src/views/chat/components/message/markdown/modules/CodeBlock/index.less rename to web-apps/ui/src/views/chat/components/message/markdown/modules/CodeBlock/index.less diff --git a/web/ui/src/views/chat/components/message/markdown/modules/CodeBlock/index.tsx b/web-apps/ui/src/views/chat/components/message/markdown/modules/CodeBlock/index.tsx similarity index 100% rename from web/ui/src/views/chat/components/message/markdown/modules/CodeBlock/index.tsx rename to web-apps/ui/src/views/chat/components/message/markdown/modules/CodeBlock/index.tsx diff --git a/web/ui/src/views/chat/components/message/message.tsx b/web-apps/ui/src/views/chat/components/message/message.tsx similarity index 100% rename from web/ui/src/views/chat/components/message/message.tsx rename to web-apps/ui/src/views/chat/components/message/message.tsx diff --git a/web/ui/src/views/chat/components/message/peer-message.tsx b/web-apps/ui/src/views/chat/components/message/peer-message.tsx similarity index 100% rename from web/ui/src/views/chat/components/message/peer-message.tsx rename to web-apps/ui/src/views/chat/components/message/peer-message.tsx diff --git a/web/ui/src/views/chat/components/message/peer.less b/web-apps/ui/src/views/chat/components/message/peer.less similarity index 100% rename from web/ui/src/views/chat/components/message/peer.less rename to web-apps/ui/src/views/chat/components/message/peer.less diff --git a/web/ui/src/views/chat/components/message/text/index.less b/web-apps/ui/src/views/chat/components/message/text/index.less similarity index 100% rename from web/ui/src/views/chat/components/message/text/index.less rename to web-apps/ui/src/views/chat/components/message/text/index.less diff --git a/web/ui/src/views/chat/components/message/text/index.tsx b/web-apps/ui/src/views/chat/components/message/text/index.tsx similarity index 100% rename from web/ui/src/views/chat/components/message/text/index.tsx rename to web-apps/ui/src/views/chat/components/message/text/index.tsx diff --git a/web/ui/src/views/chat/components/typing/index.less b/web-apps/ui/src/views/chat/components/typing/index.less similarity index 100% rename from web/ui/src/views/chat/components/typing/index.less rename to web-apps/ui/src/views/chat/components/typing/index.less diff --git a/web/ui/src/views/chat/components/typing/index.tsx b/web-apps/ui/src/views/chat/components/typing/index.tsx similarity index 100% rename from web/ui/src/views/chat/components/typing/index.tsx rename to web-apps/ui/src/views/chat/components/typing/index.tsx diff --git a/web/ui/src/views/chat/index.less b/web-apps/ui/src/views/chat/index.less similarity index 100% rename from web/ui/src/views/chat/index.less rename to web-apps/ui/src/views/chat/index.less diff --git a/web-apps/ui/src/views/chat/index.ts b/web-apps/ui/src/views/chat/index.ts new file mode 100644 index 0000000..05ce6ce --- /dev/null +++ b/web-apps/ui/src/views/chat/index.ts @@ -0,0 +1,6 @@ +export * from './module.js'; +export * from './chat-manager.js.js'; +export * from './message-manager.js.js'; +export * from './view.js'; +export * from './chat-message.js.js'; +export * from './protocol.js.js'; diff --git a/web/ui/src/views/chat/module.ts b/web-apps/ui/src/views/chat/module.ts similarity index 100% rename from web/ui/src/views/chat/module.ts rename to web-apps/ui/src/views/chat/module.ts diff --git a/web/ui/src/views/chat/view.tsx b/web-apps/ui/src/views/chat/view.tsx similarity index 100% rename from web/ui/src/views/chat/view.tsx rename to web-apps/ui/src/views/chat/view.tsx diff --git a/web/ui/src/views/debug/debug-drawer-contribution.ts b/web-apps/ui/src/views/debug/debug-drawer-contribution.ts similarity index 100% rename from web/ui/src/views/debug/debug-drawer-contribution.ts rename to web-apps/ui/src/views/debug/debug-drawer-contribution.ts diff --git a/web/ui/src/views/debug/debug-drawer.tsx b/web-apps/ui/src/views/debug/debug-drawer.tsx similarity index 100% rename from web/ui/src/views/debug/debug-drawer.tsx rename to web-apps/ui/src/views/debug/debug-drawer.tsx diff --git a/web/ui/src/views/debug/module.ts b/web-apps/ui/src/views/debug/module.ts similarity index 100% rename from web/ui/src/views/debug/module.ts rename to web-apps/ui/src/views/debug/module.ts diff --git a/web/ui/src/views/debug/protocol.ts b/web-apps/ui/src/views/debug/protocol.ts similarity index 100% rename from web/ui/src/views/debug/protocol.ts rename to web-apps/ui/src/views/debug/protocol.ts diff --git a/web/ui/src/views/knowledge/index.less b/web-apps/ui/src/views/knowledge/index.less similarity index 100% rename from web/ui/src/views/knowledge/index.less rename to web-apps/ui/src/views/knowledge/index.less diff --git a/web/ui/src/views/knowledge/index.tsx b/web-apps/ui/src/views/knowledge/index.tsx similarity index 100% rename from web/ui/src/views/knowledge/index.tsx rename to web-apps/ui/src/views/knowledge/index.tsx diff --git a/web/ui/src/views/knowledge/module.ts b/web-apps/ui/src/views/knowledge/module.ts similarity index 100% rename from web/ui/src/views/knowledge/module.ts rename to web-apps/ui/src/views/knowledge/module.ts diff --git a/web/ui/src/views/knowledge/view.tsx b/web-apps/ui/src/views/knowledge/view.tsx similarity index 100% rename from web/ui/src/views/knowledge/view.tsx rename to web-apps/ui/src/views/knowledge/view.tsx diff --git a/web/ui/src/views/protal-layout/index.less b/web-apps/ui/src/views/protal-layout/index.less similarity index 100% rename from web/ui/src/views/protal-layout/index.less rename to web-apps/ui/src/views/protal-layout/index.less diff --git a/web/ui/src/views/protal-layout/index.ts b/web-apps/ui/src/views/protal-layout/index.ts similarity index 100% rename from web/ui/src/views/protal-layout/index.ts rename to web-apps/ui/src/views/protal-layout/index.ts diff --git a/web/ui/src/views/protal-layout/module.ts b/web-apps/ui/src/views/protal-layout/module.ts similarity index 100% rename from web/ui/src/views/protal-layout/module.ts rename to web-apps/ui/src/views/protal-layout/module.ts diff --git a/web/ui/src/views/protal-layout/protocol.ts b/web-apps/ui/src/views/protal-layout/protocol.ts similarity index 100% rename from web/ui/src/views/protal-layout/protocol.ts rename to web-apps/ui/src/views/protal-layout/protocol.ts diff --git a/web/ui/src/views/protal-layout/view.tsx b/web-apps/ui/src/views/protal-layout/view.tsx similarity index 100% rename from web/ui/src/views/protal-layout/view.tsx rename to web-apps/ui/src/views/protal-layout/view.tsx diff --git a/web/ui/src/views/sessions/conversation-list/index.less b/web-apps/ui/src/views/sessions/conversation-list/index.less similarity index 100% rename from web/ui/src/views/sessions/conversation-list/index.less rename to web-apps/ui/src/views/sessions/conversation-list/index.less diff --git a/web/ui/src/views/sessions/conversation-list/index.tsx b/web-apps/ui/src/views/sessions/conversation-list/index.tsx similarity index 100% rename from web/ui/src/views/sessions/conversation-list/index.tsx rename to web-apps/ui/src/views/sessions/conversation-list/index.tsx diff --git a/web/ui/src/views/sessions/index.less b/web-apps/ui/src/views/sessions/index.less similarity index 100% rename from web/ui/src/views/sessions/index.less rename to web-apps/ui/src/views/sessions/index.less diff --git a/web/ui/src/views/sessions/module.ts b/web-apps/ui/src/views/sessions/module.ts similarity index 100% rename from web/ui/src/views/sessions/module.ts rename to web-apps/ui/src/views/sessions/module.ts diff --git a/web/ui/src/views/sessions/view.tsx b/web-apps/ui/src/views/sessions/view.tsx similarity index 100% rename from web/ui/src/views/sessions/view.tsx rename to web-apps/ui/src/views/sessions/view.tsx diff --git a/web/ui/src/views/tools/index.less b/web-apps/ui/src/views/tools/index.less similarity index 100% rename from web/ui/src/views/tools/index.less rename to web-apps/ui/src/views/tools/index.less diff --git a/web/ui/src/views/tools/index.tsx b/web-apps/ui/src/views/tools/index.tsx similarity index 100% rename from web/ui/src/views/tools/index.tsx rename to web-apps/ui/src/views/tools/index.tsx diff --git a/web/ui/src/views/tools/module.ts b/web-apps/ui/src/views/tools/module.ts similarity index 100% rename from web/ui/src/views/tools/module.ts rename to web-apps/ui/src/views/tools/module.ts diff --git a/web/ui/src/views/tools/view.tsx b/web-apps/ui/src/views/tools/view.tsx similarity index 100% rename from web/ui/src/views/tools/view.tsx rename to web-apps/ui/src/views/tools/view.tsx diff --git a/web/ui/tsconfig.json b/web-apps/ui/tsconfig.json similarity index 100% rename from web/ui/tsconfig.json rename to web-apps/ui/tsconfig.json diff --git a/web/ui/typings.d.ts b/web-apps/ui/typings.d.ts similarity index 100% rename from web/ui/typings.d.ts rename to web-apps/ui/typings.d.ts diff --git a/web/ui/typings/index.d.ts b/web-apps/ui/typings/index.d.ts similarity index 100% rename from web/ui/typings/index.d.ts rename to web-apps/ui/typings/index.d.ts diff --git a/web/packages/magent-core/.eslintrc.mjs b/web-packages/magent-core/.eslintrc.mjs similarity index 100% rename from web/packages/magent-core/.eslintrc.mjs rename to web-packages/magent-core/.eslintrc.mjs diff --git a/web/packages/magent-core/.fatherrc.ts b/web-packages/magent-core/.fatherrc.ts similarity index 100% rename from web/packages/magent-core/.fatherrc.ts rename to web-packages/magent-core/.fatherrc.ts diff --git a/web/packages/magent-flow/src/components/Node/index.tsx b/web-packages/magent-core/CHANGELOG.md similarity index 100% rename from web/packages/magent-flow/src/components/Node/index.tsx rename to web-packages/magent-core/CHANGELOG.md diff --git a/web/packages/magent-core/README.md b/web-packages/magent-core/README.md similarity index 100% rename from web/packages/magent-core/README.md rename to web-packages/magent-core/README.md diff --git a/web/packages/magent-core/babel.config.json b/web-packages/magent-core/babel.config.json similarity index 100% rename from web/packages/magent-core/babel.config.json rename to web-packages/magent-core/babel.config.json diff --git a/web/packages/magent-core/jest.config.mjs b/web-packages/magent-core/jest.config.mjs similarity index 100% rename from web/packages/magent-core/jest.config.mjs rename to web-packages/magent-core/jest.config.mjs diff --git a/web/packages/magent-core/package.json b/web-packages/magent-core/package.json similarity index 100% rename from web/packages/magent-core/package.json rename to web-packages/magent-core/package.json diff --git a/web/packages/magent-core/src/index.spec.ts b/web-packages/magent-core/src/index.spec.ts similarity index 100% rename from web/packages/magent-core/src/index.spec.ts rename to web-packages/magent-core/src/index.spec.ts diff --git a/web/packages/magent-core/src/index.ts b/web-packages/magent-core/src/index.ts similarity index 100% rename from web/packages/magent-core/src/index.ts rename to web-packages/magent-core/src/index.ts diff --git a/web/packages/magent-core/tsconfig.json b/web-packages/magent-core/tsconfig.json similarity index 53% rename from web/packages/magent-core/tsconfig.json rename to web-packages/magent-core/tsconfig.json index de04ac0..c2d9e21 100644 --- a/web/packages/magent-core/tsconfig.json +++ b/web-packages/magent-core/tsconfig.json @@ -1,9 +1,10 @@ { - "extends": "../../../tsconfig.base.json", + "extends": "../../tsconfig.base.json", "compilerOptions": { "rootDir": "./src", - "outDir": "es", - "declarationDir": "es" + "declaration": true, + "declarationDir": "es", + "outDir": "es" }, "types": ["jest"], "exclude": ["node_modules"], diff --git a/web/packages/magent-flow/.eslintrc.mjs b/web-packages/magent-flow/.eslintrc.mjs similarity index 100% rename from web/packages/magent-flow/.eslintrc.mjs rename to web-packages/magent-flow/.eslintrc.mjs diff --git a/web/packages/magent-flow/.fatherrc.ts b/web-packages/magent-flow/.fatherrc.ts similarity index 100% rename from web/packages/magent-flow/.fatherrc.ts rename to web-packages/magent-flow/.fatherrc.ts diff --git a/web/packages/magent-flow/.gitignore b/web-packages/magent-flow/.gitignore similarity index 100% rename from web/packages/magent-flow/.gitignore rename to web-packages/magent-flow/.gitignore diff --git a/web/packages/magent-flow/.stylelintignore b/web-packages/magent-flow/.stylelintignore similarity index 100% rename from web/packages/magent-flow/.stylelintignore rename to web-packages/magent-flow/.stylelintignore diff --git a/web-packages/magent-flow/CHANGELOG.md b/web-packages/magent-flow/CHANGELOG.md new file mode 100644 index 0000000..e69de29 diff --git a/web/packages/magent-flow/README.md b/web-packages/magent-flow/README.md similarity index 100% rename from web/packages/magent-flow/README.md rename to web-packages/magent-flow/README.md diff --git a/web-packages/magent-flow/babel.config.json b/web-packages/magent-flow/babel.config.json new file mode 100644 index 0000000..89403e9 --- /dev/null +++ b/web-packages/magent-flow/babel.config.json @@ -0,0 +1,13 @@ +{ + "presets": [ + "@babel/preset-env", + [ + "@babel/preset-react", + { + "runtime": "automatic" + } + ], + "@babel/preset-typescript" + ], + "plugins": [] +} diff --git a/web/packages/magent-flow/jest.config.mjs b/web-packages/magent-flow/jest.config.mjs similarity index 100% rename from web/packages/magent-flow/jest.config.mjs rename to web-packages/magent-flow/jest.config.mjs diff --git a/web/packages/magent-flow/package.json b/web-packages/magent-flow/package.json similarity index 92% rename from web/packages/magent-flow/package.json rename to web-packages/magent-flow/package.json index 770776b..3a1285b 100644 --- a/web/packages/magent-flow/package.json +++ b/web-packages/magent-flow/package.json @@ -34,7 +34,7 @@ ], "scripts": { "setup": "father build", - "build": "father build", + "build": "pnpm run build:tailwind && father build", "test": ": Note: lint task is delegated to test:* scripts", "test:vitest": "vitest run", "test:jest": "jest", @@ -43,12 +43,12 @@ "coverage:jest": "jest --coverage", "lint": ": Note: lint task is delegated to lint:* scripts", "lint:eslint": "eslint src", + "build:tailwind": "tailwindcss -i ./src/tailwind.css -o ./src/tailwind.out.css", "tailwind": "tailwindcss -i ./src/tailwind.css -o ./src/tailwind.out.css --watch", "typecheck:tsc": "tsc --noEmit" }, "dependencies": { "@ant-design/icons": "^5.1.0", - "@babel/runtime": "^7.18.0", "@floating-ui/react": "^0.26.22", "@lexical/code": "^0.17.0", "@lexical/react": "^0.17.0", @@ -56,13 +56,12 @@ "@types/json-schema": "^7.0.15", "@xyflow/react": "^12.0.2", "ahooks": "^3.8.1", - "ajv": "^8.17.1", "antd": "^5.19.2", "classnames": "^2.3.2", "js-yaml": "^4.1.0", "lexical": "^0.17.0", "lodash": "^4.17.21", - "react": "^18.0.0", + "react": "^18.2.0", "react-dom": "^18.0.0", "react-hotkeys-hook": "^4.5.0", "short-unique-id": "^5.2.0", diff --git a/web/packages/magent-flow/src/FormSchema/index.ts b/web-packages/magent-flow/src/FormSchema/index.ts similarity index 100% rename from web/packages/magent-flow/src/FormSchema/index.ts rename to web-packages/magent-flow/src/FormSchema/index.ts diff --git a/web/packages/magent-flow/src/RefForm/index.md b/web-packages/magent-flow/src/RefForm/index.md similarity index 100% rename from web/packages/magent-flow/src/RefForm/index.md rename to web-packages/magent-flow/src/RefForm/index.md diff --git a/web/packages/magent-flow/src/RefForm/index.tsx b/web-packages/magent-flow/src/RefForm/index.tsx similarity index 100% rename from web/packages/magent-flow/src/RefForm/index.tsx rename to web-packages/magent-flow/src/RefForm/index.tsx diff --git a/web/packages/magent-flow/src/SchemaConfigForm/index.md b/web-packages/magent-flow/src/SchemaConfigForm/index.md similarity index 100% rename from web/packages/magent-flow/src/SchemaConfigForm/index.md rename to web-packages/magent-flow/src/SchemaConfigForm/index.md diff --git a/web/packages/magent-flow/src/SchemaConfigForm/index.tsx b/web-packages/magent-flow/src/SchemaConfigForm/index.tsx similarity index 100% rename from web/packages/magent-flow/src/SchemaConfigForm/index.tsx rename to web-packages/magent-flow/src/SchemaConfigForm/index.tsx diff --git a/web/packages/magent-flow/src/common/icons.ts b/web-packages/magent-flow/src/common/icons.ts similarity index 100% rename from web/packages/magent-flow/src/common/icons.ts rename to web-packages/magent-flow/src/common/icons.ts diff --git a/web/packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx b/web-packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx rename to web-packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/CollapseWrapper/index.tsx b/web-packages/magent-flow/src/components/AIBasic/CollapseWrapper/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/CollapseWrapper/index.tsx rename to web-packages/magent-flow/src/components/AIBasic/CollapseWrapper/index.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx b/web-packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx rename to web-packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/constants.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/constants.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/constants.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/constants.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/hooks.ts diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/hooks.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/menu.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/menu.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/menu.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/menu.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/prompt-option.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/variable-option.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/custom-text/node.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/on-blur-or-focus-block.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-block/index.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/index.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/node.tsx diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/utils.ts b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/utils.ts similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/utils.ts rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/variable-value-block/utils.ts diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/types.ts b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/types.ts similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/types.ts rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/types.ts diff --git a/web/packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts rename to web-packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts diff --git a/web/packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx b/web-packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx rename to web-packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx diff --git a/web/packages/magent-flow/src/components/CustomEdge/index.tsx b/web-packages/magent-flow/src/components/CustomEdge/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/CustomEdge/index.tsx rename to web-packages/magent-flow/src/components/CustomEdge/index.tsx diff --git a/web/packages/magent-flow/src/components/Flow/index.tsx b/web-packages/magent-flow/src/components/Flow/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Flow/index.tsx rename to web-packages/magent-flow/src/components/Flow/index.tsx diff --git a/web/packages/magent-flow/src/components/Flow/keys.ts b/web-packages/magent-flow/src/components/Flow/keys.ts similarity index 100% rename from web/packages/magent-flow/src/components/Flow/keys.ts rename to web-packages/magent-flow/src/components/Flow/keys.ts diff --git a/web/packages/magent-flow/src/components/FlowController/index.tsx b/web-packages/magent-flow/src/components/FlowController/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/FlowController/index.tsx rename to web-packages/magent-flow/src/components/FlowController/index.tsx diff --git a/web/packages/magent-flow/src/components/FlowWithPanel/index.tsx b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/FlowWithPanel/index.tsx rename to web-packages/magent-flow/src/components/FlowWithPanel/index.tsx diff --git a/web/packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml b/web-packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml similarity index 100% rename from web/packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml rename to web-packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml diff --git a/web/packages/magent-flow/src/components/Node/AgentNode/index.tsx b/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Node/AgentNode/index.tsx rename to web-packages/magent-flow/src/components/Node/AgentNode/index.tsx diff --git a/web/packages/magent-flow/src/components/Node/CommonNode/index.tsx b/web-packages/magent-flow/src/components/Node/CommonNode/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Node/CommonNode/index.tsx rename to web-packages/magent-flow/src/components/Node/CommonNode/index.tsx diff --git a/web/packages/magent-flow/src/components/Node/EndNode/index.tsx b/web-packages/magent-flow/src/components/Node/EndNode/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Node/EndNode/index.tsx rename to web-packages/magent-flow/src/components/Node/EndNode/index.tsx diff --git a/web/packages/magent-flow/src/components/Node/IfElseNode/index.tsx b/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Node/IfElseNode/index.tsx rename to web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx diff --git a/web/packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx b/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx rename to web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx diff --git a/web/packages/magent-flow/src/components/Node/LLMNode/index.tsx b/web-packages/magent-flow/src/components/Node/LLMNode/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Node/LLMNode/index.tsx rename to web-packages/magent-flow/src/components/Node/LLMNode/index.tsx diff --git a/web/packages/magent-flow/src/components/Node/NodeWrapper/Header/index.tsx b/web-packages/magent-flow/src/components/Node/NodeWrapper/Header/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Node/NodeWrapper/Header/index.tsx rename to web-packages/magent-flow/src/components/Node/NodeWrapper/Header/index.tsx diff --git a/web/packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx b/web-packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx rename to web-packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx diff --git a/web/packages/magent-flow/src/components/Node/NodeWrapper/index.tsx b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Node/NodeWrapper/index.tsx rename to web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx diff --git a/web/packages/magent-flow/src/components/Node/StartNode/index.tsx b/web-packages/magent-flow/src/components/Node/StartNode/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/Node/StartNode/index.tsx rename to web-packages/magent-flow/src/components/Node/StartNode/index.tsx diff --git a/web-packages/magent-flow/src/components/Node/index.tsx b/web-packages/magent-flow/src/components/Node/index.tsx new file mode 100644 index 0000000..e69de29 diff --git a/web/packages/magent-flow/src/components/NodePanel/index.tsx b/web-packages/magent-flow/src/components/NodePanel/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/NodePanel/index.tsx rename to web-packages/magent-flow/src/components/NodePanel/index.tsx diff --git a/web/packages/magent-flow/src/components/RefForm/index.md b/web-packages/magent-flow/src/components/RefForm/index.md similarity index 100% rename from web/packages/magent-flow/src/components/RefForm/index.md rename to web-packages/magent-flow/src/components/RefForm/index.md diff --git a/web/packages/magent-flow/src/components/ReferenceForm/index.tsx b/web-packages/magent-flow/src/components/ReferenceForm/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/ReferenceForm/index.tsx rename to web-packages/magent-flow/src/components/ReferenceForm/index.tsx diff --git a/web/packages/magent-flow/src/components/ReferenceSelect/index.tsx b/web-packages/magent-flow/src/components/ReferenceSelect/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/ReferenceSelect/index.tsx rename to web-packages/magent-flow/src/components/ReferenceSelect/index.tsx diff --git a/web/packages/magent-flow/src/components/VariableForm/index.tsx b/web-packages/magent-flow/src/components/VariableForm/index.tsx similarity index 100% rename from web/packages/magent-flow/src/components/VariableForm/index.tsx rename to web-packages/magent-flow/src/components/VariableForm/index.tsx diff --git a/web/packages/magent-flow/src/constants/constant.ts b/web-packages/magent-flow/src/constants/constant.ts similarity index 100% rename from web/packages/magent-flow/src/constants/constant.ts rename to web-packages/magent-flow/src/constants/constant.ts diff --git a/web/packages/magent-flow/src/context/event-emitter.tsx b/web-packages/magent-flow/src/context/event-emitter.tsx similarity index 100% rename from web/packages/magent-flow/src/context/event-emitter.tsx rename to web-packages/magent-flow/src/context/event-emitter.tsx diff --git a/web/packages/magent-flow/src/index.ts b/web-packages/magent-flow/src/index.ts similarity index 100% rename from web/packages/magent-flow/src/index.ts rename to web-packages/magent-flow/src/index.ts diff --git a/web/packages/magent-flow/src/interfaces/flow.ts b/web-packages/magent-flow/src/interfaces/flow.ts similarity index 100% rename from web/packages/magent-flow/src/interfaces/flow.ts rename to web-packages/magent-flow/src/interfaces/flow.ts diff --git a/web/packages/magent-flow/src/spec/FormSchema/index.ts b/web-packages/magent-flow/src/spec/FormSchema/index.ts similarity index 100% rename from web/packages/magent-flow/src/spec/FormSchema/index.ts rename to web-packages/magent-flow/src/spec/FormSchema/index.ts diff --git a/web/packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap b/web-packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap similarity index 100% rename from web/packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap rename to web-packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap diff --git a/web/packages/magent-flow/src/spec/node.test.ts b/web-packages/magent-flow/src/spec/node.test.ts similarity index 100% rename from web/packages/magent-flow/src/spec/node.test.ts rename to web-packages/magent-flow/src/spec/node.test.ts diff --git a/web/packages/magent-flow/src/spec/node.ts b/web-packages/magent-flow/src/spec/node.ts similarity index 100% rename from web/packages/magent-flow/src/spec/node.ts rename to web-packages/magent-flow/src/spec/node.ts diff --git a/web/packages/magent-flow/src/spec/test-jsonschema.json b/web-packages/magent-flow/src/spec/test-jsonschema.json similarity index 100% rename from web/packages/magent-flow/src/spec/test-jsonschema.json rename to web-packages/magent-flow/src/spec/test-jsonschema.json diff --git a/web/packages/magent-flow/src/spec/uuid.ts b/web-packages/magent-flow/src/spec/uuid.ts similarity index 100% rename from web/packages/magent-flow/src/spec/uuid.ts rename to web-packages/magent-flow/src/spec/uuid.ts diff --git a/web/packages/magent-flow/src/stores/useFlowStore.ts b/web-packages/magent-flow/src/stores/useFlowStore.ts similarity index 100% rename from web/packages/magent-flow/src/stores/useFlowStore.ts rename to web-packages/magent-flow/src/stores/useFlowStore.ts diff --git a/web/packages/magent-flow/src/stores/useKnowledgeStore.ts b/web-packages/magent-flow/src/stores/useKnowledgeStore.ts similarity index 100% rename from web/packages/magent-flow/src/stores/useKnowledgeStore.ts rename to web-packages/magent-flow/src/stores/useKnowledgeStore.ts diff --git a/web/packages/magent-flow/src/stores/useModelStore.ts b/web-packages/magent-flow/src/stores/useModelStore.ts similarity index 100% rename from web/packages/magent-flow/src/stores/useModelStore.ts rename to web-packages/magent-flow/src/stores/useModelStore.ts diff --git a/web/packages/magent-flow/src/stores/useShortcutsStore.ts b/web-packages/magent-flow/src/stores/useShortcutsStore.ts similarity index 100% rename from web/packages/magent-flow/src/stores/useShortcutsStore.ts rename to web-packages/magent-flow/src/stores/useShortcutsStore.ts diff --git a/web/packages/magent-flow/src/stores/useUndoRedoStore.ts b/web-packages/magent-flow/src/stores/useUndoRedoStore.ts similarity index 100% rename from web/packages/magent-flow/src/stores/useUndoRedoStore.ts rename to web-packages/magent-flow/src/stores/useUndoRedoStore.ts diff --git a/web/packages/magent-flow/src/tailwind.css b/web-packages/magent-flow/src/tailwind.css similarity index 100% rename from web/packages/magent-flow/src/tailwind.css rename to web-packages/magent-flow/src/tailwind.css diff --git a/web/packages/magent-flow/src/utils/basic.ts b/web-packages/magent-flow/src/utils/basic.ts similarity index 100% rename from web/packages/magent-flow/src/utils/basic.ts rename to web-packages/magent-flow/src/utils/basic.ts diff --git a/web/packages/magent-flow/src/utils/index.tsx b/web-packages/magent-flow/src/utils/index.tsx similarity index 100% rename from web/packages/magent-flow/src/utils/index.tsx rename to web-packages/magent-flow/src/utils/index.tsx diff --git a/web/packages/magent-flow/src/utils/reactflowUtils.ts b/web-packages/magent-flow/src/utils/reactflowUtils.ts similarity index 100% rename from web/packages/magent-flow/src/utils/reactflowUtils.ts rename to web-packages/magent-flow/src/utils/reactflowUtils.ts diff --git a/web/packages/magent-flow/src/utils/wrappedClass.ts b/web-packages/magent-flow/src/utils/wrappedClass.ts similarity index 100% rename from web/packages/magent-flow/src/utils/wrappedClass.ts rename to web-packages/magent-flow/src/utils/wrappedClass.ts diff --git a/web/packages/magent-flow/tailwind.config.js b/web-packages/magent-flow/tailwind.config.js similarity index 100% rename from web/packages/magent-flow/tailwind.config.js rename to web-packages/magent-flow/tailwind.config.js diff --git a/web/packages/magent-flow/tsconfig.json b/web-packages/magent-flow/tsconfig.json similarity index 83% rename from web/packages/magent-flow/tsconfig.json rename to web-packages/magent-flow/tsconfig.json index e7a514f..e601a98 100644 --- a/web/packages/magent-flow/tsconfig.json +++ b/web-packages/magent-flow/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.base.json", + "extends": "../../tsconfig.base.json", "compilerOptions": { "rootDir": "./src", "outDir": "es", diff --git a/web/packages/magent-core/CHANGELOG.md b/web/packages/magent-core/CHANGELOG.md deleted file mode 100644 index 1ed2e86..0000000 --- a/web/packages/magent-core/CHANGELOG.md +++ /dev/null @@ -1,402 +0,0 @@ -# @difizen/libro-core - -## 0.1.33 - -### Patch Changes - -- 4811299: fix dark theme style -- Updated dependencies [4811299] - - @difizen/libro-code-editor@0.1.33 - - @difizen/libro-common@0.1.33 - - @difizen/libro-shared-model@0.1.33 - - @difizen/libro-virtualized@0.1.33 - -## 0.1.32 - -### Patch Changes - -- 2d90b29: fix(core): add deprecated -- Updated dependencies [2d90b29] - - @difizen/libro-code-editor@0.1.32 - - @difizen/libro-common@0.1.32 - - @difizen/libro-shared-model@0.1.32 - - @difizen/libro-virtualized@0.1.32 - -## 0.1.31 - -### Patch Changes - -- 3a07805: use modelId for modelCache -- 5b23c6d: Jupyter: integrate jupyter-widgets -- Updated dependencies [3a07805] -- Updated dependencies [5b23c6d] - - @difizen/libro-code-editor@0.1.31 - - @difizen/libro-common@0.1.31 - - @difizen/libro-shared-model@0.1.31 - - @difizen/libro-virtualized@0.1.31 - -## 0.1.30 - -### Patch Changes - -- 3c95a2c: improve keybind panel style -- Updated dependencies [3c95a2c] - - @difizen/libro-code-editor@0.1.30 - - @difizen/libro-common@0.1.30 - - @difizen/libro-shared-model@0.1.30 - - @difizen/libro-virtualized@0.1.30 - -## 0.1.29 - -### Patch Changes - -- d81dd35: Prompt: Migrate libro_server to libro_ai -- d661508: Lab: open file after creation -- Updated dependencies [d81dd35] -- Updated dependencies [d661508] - - @difizen/libro-shared-model@0.1.29 - - @difizen/libro-code-editor@0.1.29 - - @difizen/libro-virtualized@0.1.29 - - @difizen/libro-common@0.1.29 - -## 0.1.28 - -### Patch Changes - -- cc94f1d: 1.refactor(jupyter): use ContentSaveContribution -- Updated dependencies [cc94f1d] - - @difizen/libro-code-editor@0.1.28 - - @difizen/libro-common@0.1.28 - - @difizen/libro-shared-model@0.1.28 - - @difizen/libro-virtualized@0.1.28 - -## 0.1.27 - -### Patch Changes - -- 5341bd6: feat: go to definition - feat: signature help -- Updated dependencies [5341bd6] - - @difizen/libro-code-editor@0.1.27 - - @difizen/libro-common@0.1.27 - - @difizen/libro-shared-model@0.1.27 - - @difizen/libro-virtualized@0.1.27 - -## 0.1.26 - -### Patch Changes - -- 6a520ad: fix: add import file extension -- Updated dependencies [6a520ad] - - @difizen/libro-code-editor@0.1.26 - - @difizen/libro-virtualized@0.1.26 - - @difizen/libro-common@0.1.26 - - @difizen/libro-shared-model@0.1.26 - -## 0.1.24 - -### Patch Changes - -- 1bcfbee: 1.fix: get correct url when create notebook file 2.chore: update the peerDependencies about react -- Updated dependencies [1bcfbee] - - @difizen/libro-code-editor@0.1.24 - - @difizen/libro-virtualized@0.1.24 - - @difizen/libro-common@0.1.24 - -## 0.1.23 - -### Patch Changes - -- e37f319: fix: remove useless code about format button -- Updated dependencies [e37f319] - - @difizen/libro-code-editor@0.1.23 - - @difizen/libro-common@0.1.23 - - @difizen/libro-shared-model@0.1.23 - - @difizen/libro-virtualized@0.1.23 - -## 0.1.22 - -### Patch Changes - -- 669e05b: fix: valid notebook - feat(jupyter): add restart kernel - fix: poll kernelSpec after serverManager ready -- Updated dependencies [669e05b] - - @difizen/libro-code-editor@0.1.22 - - @difizen/libro-common@0.1.22 - - @difizen/libro-shared-model@0.1.22 - - @difizen/libro-virtualized@0.1.22 - -## 0.1.21 - -### Patch Changes - -- 9da4081: 1.fix: search view hide not focus libro view -- Updated dependencies [9da4081] - - @difizen/libro-code-editor@0.1.21 - - @difizen/libro-common@0.1.21 - - @difizen/libro-shared-model@0.1.21 - - @difizen/libro-virtualized@0.1.21 - -## 0.1.20 - -### Patch Changes - -- f3924d3: 1.fix search scroll on large cell 2.add libroModel in VirtualizedManager -- Updated dependencies [f3924d3] - - @difizen/libro-code-editor@0.1.20 - - @difizen/libro-common@0.1.20 - - @difizen/libro-shared-model@0.1.20 - - @difizen/libro-virtualized@0.1.20 - -## 0.1.19 - -### Patch Changes - -- fe3ee51: fix:poll kernels when serverManager ready -- Updated dependencies [fe3ee51] - - @difizen/libro-code-editor@0.1.19 - - @difizen/libro-common@0.1.19 - - @difizen/libro-shared-model@0.1.19 - - @difizen/libro-virtualized@0.1.19 - -## 0.1.18 - -### Patch Changes - -- f7c6839: File uploads can now be triggered by right-clicking on the file tree. -- 0f9e69d: Lab supports saving of all code files. -- 0f9e69d: More user-friendly prompt cell setting operation. -- Updated dependencies [f7c6839] -- Updated dependencies [0f9e69d] -- Updated dependencies [0f9e69d] - - @difizen/libro-shared-model@0.1.18 - - @difizen/libro-code-editor@0.1.18 - - @difizen/libro-virtualized@0.1.18 - - @difizen/libro-common@0.1.18 - -## 0.1.17 - -### Patch Changes - -- b159277: insert and execute output in a cell -- 9ff1bf9: Support file download. -- Updated dependencies [b159277] -- Updated dependencies [9ff1bf9] - - @difizen/libro-code-editor@0.1.17 - - @difizen/libro-common@0.1.17 - - @difizen/libro-shared-model@0.1.17 - - @difizen/libro-virtualized@0.1.17 - -## 0.1.16 - -### Patch Changes - -- 7d1edf3: Fix: Make Terminals opened from left panel same as the one you created, instead of creating a new terminal view. -- 90f6f8e: Fix: Cancel observing outputs height change' -- Updated dependencies [7d1edf3] -- Updated dependencies [90f6f8e] - - @difizen/libro-code-editor@0.1.16 - - @difizen/libro-common@0.1.16 - - @difizen/libro-shared-model@0.1.16 - - @difizen/libro-virtualized@0.1.16 - -## 0.1.15 - -### Patch Changes - -- 1b88a16: Feature: Better Prompt cell! Now based on better prompt magic support, you can use prompt cells to chat directly with OpenAI models. And you can put chats in context and create exciting workflows. -- Updated dependencies [1b88a16] - - @difizen/libro-shared-model@0.1.15 - - @difizen/libro-code-editor@0.1.15 - - @difizen/libro-virtualized@0.1.15 - - @difizen/libro-common@0.1.15 - -## 0.1.14 - -### Patch Changes - -- 0b882d3: 1. prompt cell adapt to the api of libro-server 2.fix the editor in CodeEditorView is undefined -- Updated dependencies [0b882d3] - - @difizen/libro-code-editor@0.1.14 - - @difizen/libro-common@0.1.14 - - @difizen/libro-shared-model@0.1.14 - - @difizen/libro-virtualized@0.1.14 - -## 0.1.13 - -### Patch Changes - -- 262ba79: 1. fix the editor in CodeEditorView is undefined -- Updated dependencies [262ba79] - - @difizen/libro-code-editor@0.1.13 - - @difizen/libro-common@0.1.13 - - @difizen/libro-shared-model@0.1.13 - - @difizen/libro-virtualized@0.1.13 - -## 0.1.12 - -### Patch Changes - -- bf45fa2: 1. fix:close the open tab when delete the file 2. stop propagation when focus cell right toolbar -- Updated dependencies [bf45fa2] - - @difizen/libro-code-editor@0.1.12 - - @difizen/libro-common@0.1.12 - - @difizen/libro-shared-model@0.1.12 - - @difizen/libro-virtualized@0.1.12 - -## 0.1.11 - -### Patch Changes - -- 236634d: 1.libro keybind not work when switching tabs - 2.auto focus when input file name. - 3.editor resize when CodeEditorViewer resize - 4.add file size warning - 5.add UI for file formats not supported for viewing - 6.file name error when select other format -- Updated dependencies [236634d] - - @difizen/libro-code-editor@0.1.11 - - @difizen/libro-common@0.1.11 - - @difizen/libro-shared-model@0.1.11 - - @difizen/libro-virtualized@0.1.11 - -## 0.1.10 - -### Patch Changes - -- ccdd12d: 1. add remove action in file tree menu -- Updated dependencies [ccdd12d] - - @difizen/libro-code-editor@0.1.10 - - @difizen/libro-common@0.1.10 - - @difizen/libro-shared-model@0.1.10 - - @difizen/libro-virtualized@0.1.10 - -## 0.1.9 - -### Patch Changes - -- ad803e2: 1. use codeEditorViewer as the last resort file viewer. 2. fix terminal -- Updated dependencies [ad803e2] - - @difizen/libro-code-editor@0.1.9 - - @difizen/libro-common@0.1.9 - - @difizen/libro-shared-model@0.1.9 - - @difizen/libro-virtualized@0.1.9 - -## 0.1.8 - -### Patch Changes - -- 1. Support json and other file formats. - 2. Dynamic shortcut keys and menus when switching tabs. -- Updated dependencies - - @difizen/libro-code-editor@0.1.8 - - @difizen/libro-common@0.1.8 - - @difizen/libro-shared-model@0.1.8 - - @difizen/libro-virtualized@0.1.8 - -## 0.1.7 - -### Patch Changes - -- Clean lab modules. -- Updated dependencies - - @difizen/libro-code-editor@0.1.7 - - @difizen/libro-common@0.1.7 - - @difizen/libro-shared-model@0.1.7 - - @difizen/libro-virtualized@0.1.7 - -## 0.1.6 - -### Patch Changes - -- Support code file editing. -- Updated dependencies - - @difizen/libro-code-editor@0.1.6 - - @difizen/libro-common@0.1.6 - - @difizen/libro-shared-model@0.1.6 - - @difizen/libro-virtualized@0.1.6 - -## 0.1.5 - -### Patch Changes - -- 1. Support image preview. - 2. Export the definition and implementation of the libro lab module. -- Updated dependencies - - @difizen/libro-code-editor@0.1.5 - - @difizen/libro-common@0.1.5 - - @difizen/libro-shared-model@0.1.5 - - @difizen/libro-virtualized@0.1.5 - -## 0.1.4 - -### Patch Changes - -- Fix issues with lsp and virtual list. -- Updated dependencies - - @difizen/libro-code-editor@0.1.4 - - @difizen/libro-virtualized@0.1.4 - - @difizen/libro-common@0.1.4 - - @difizen/libro-shared-model@0.1.4 - -## 0.1.3 - -### Patch Changes - -- Fix the content format issue of prompt cell -- Updated dependencies - - @difizen/libro-code-editor@0.1.3 - - @difizen/libro-common@0.1.3 - - @difizen/libro-shared-model@0.1.3 - - @difizen/libro-virtualized@0.1.3 - -## 0.1.2 - -### Patch Changes - -- 1. Support monaco editor, code cell is migrated to monaco editor by default. - 2. Support virtual lists to improve performance. - 3. libro lab can now use terminal. -- Updated dependencies - - @difizen/libro-code-editor@0.1.2 - - @difizen/libro-common@0.1.2 - - @difizen/libro-shared-model@0.1.2 - - @difizen/libro-virtualized@0.1.2 - -## 0.1.1 - -### Patch Changes - -- 1. Prompt cell is now available 🎉. - 2. Better lab UI. -- Updated dependencies - - @difizen/libro-code-editor@0.1.1 - - @difizen/libro-common@0.1.1 - - @difizen/libro-shared-model@0.1.1 - -## 0.1.0 - -### Minor Changes - -- 1. All modules used to support the notebook editor. - 2. Support lab products. - -### Patch Changes - -- 127cb35: Initia version -- Updated dependencies [127cb35] -- Updated dependencies - - @difizen/libro-code-editor@0.1.0 - - @difizen/libro-common@0.1.0 - - @difizen/libro-shared-model@0.1.0 - -## 0.0.2-alpha.0 - -### Patch Changes - -- Initia version -- Updated dependencies - - @difizen/libro-code-editor@0.0.2-alpha.0 - - @difizen/libro-common@0.0.2-alpha.0 - - @difizen/libro-shared-model@0.0.2-alpha.0 diff --git a/web/packages/magent-flow/CHANGELOG.md b/web/packages/magent-flow/CHANGELOG.md deleted file mode 100644 index 1ed2e86..0000000 --- a/web/packages/magent-flow/CHANGELOG.md +++ /dev/null @@ -1,402 +0,0 @@ -# @difizen/libro-core - -## 0.1.33 - -### Patch Changes - -- 4811299: fix dark theme style -- Updated dependencies [4811299] - - @difizen/libro-code-editor@0.1.33 - - @difizen/libro-common@0.1.33 - - @difizen/libro-shared-model@0.1.33 - - @difizen/libro-virtualized@0.1.33 - -## 0.1.32 - -### Patch Changes - -- 2d90b29: fix(core): add deprecated -- Updated dependencies [2d90b29] - - @difizen/libro-code-editor@0.1.32 - - @difizen/libro-common@0.1.32 - - @difizen/libro-shared-model@0.1.32 - - @difizen/libro-virtualized@0.1.32 - -## 0.1.31 - -### Patch Changes - -- 3a07805: use modelId for modelCache -- 5b23c6d: Jupyter: integrate jupyter-widgets -- Updated dependencies [3a07805] -- Updated dependencies [5b23c6d] - - @difizen/libro-code-editor@0.1.31 - - @difizen/libro-common@0.1.31 - - @difizen/libro-shared-model@0.1.31 - - @difizen/libro-virtualized@0.1.31 - -## 0.1.30 - -### Patch Changes - -- 3c95a2c: improve keybind panel style -- Updated dependencies [3c95a2c] - - @difizen/libro-code-editor@0.1.30 - - @difizen/libro-common@0.1.30 - - @difizen/libro-shared-model@0.1.30 - - @difizen/libro-virtualized@0.1.30 - -## 0.1.29 - -### Patch Changes - -- d81dd35: Prompt: Migrate libro_server to libro_ai -- d661508: Lab: open file after creation -- Updated dependencies [d81dd35] -- Updated dependencies [d661508] - - @difizen/libro-shared-model@0.1.29 - - @difizen/libro-code-editor@0.1.29 - - @difizen/libro-virtualized@0.1.29 - - @difizen/libro-common@0.1.29 - -## 0.1.28 - -### Patch Changes - -- cc94f1d: 1.refactor(jupyter): use ContentSaveContribution -- Updated dependencies [cc94f1d] - - @difizen/libro-code-editor@0.1.28 - - @difizen/libro-common@0.1.28 - - @difizen/libro-shared-model@0.1.28 - - @difizen/libro-virtualized@0.1.28 - -## 0.1.27 - -### Patch Changes - -- 5341bd6: feat: go to definition - feat: signature help -- Updated dependencies [5341bd6] - - @difizen/libro-code-editor@0.1.27 - - @difizen/libro-common@0.1.27 - - @difizen/libro-shared-model@0.1.27 - - @difizen/libro-virtualized@0.1.27 - -## 0.1.26 - -### Patch Changes - -- 6a520ad: fix: add import file extension -- Updated dependencies [6a520ad] - - @difizen/libro-code-editor@0.1.26 - - @difizen/libro-virtualized@0.1.26 - - @difizen/libro-common@0.1.26 - - @difizen/libro-shared-model@0.1.26 - -## 0.1.24 - -### Patch Changes - -- 1bcfbee: 1.fix: get correct url when create notebook file 2.chore: update the peerDependencies about react -- Updated dependencies [1bcfbee] - - @difizen/libro-code-editor@0.1.24 - - @difizen/libro-virtualized@0.1.24 - - @difizen/libro-common@0.1.24 - -## 0.1.23 - -### Patch Changes - -- e37f319: fix: remove useless code about format button -- Updated dependencies [e37f319] - - @difizen/libro-code-editor@0.1.23 - - @difizen/libro-common@0.1.23 - - @difizen/libro-shared-model@0.1.23 - - @difizen/libro-virtualized@0.1.23 - -## 0.1.22 - -### Patch Changes - -- 669e05b: fix: valid notebook - feat(jupyter): add restart kernel - fix: poll kernelSpec after serverManager ready -- Updated dependencies [669e05b] - - @difizen/libro-code-editor@0.1.22 - - @difizen/libro-common@0.1.22 - - @difizen/libro-shared-model@0.1.22 - - @difizen/libro-virtualized@0.1.22 - -## 0.1.21 - -### Patch Changes - -- 9da4081: 1.fix: search view hide not focus libro view -- Updated dependencies [9da4081] - - @difizen/libro-code-editor@0.1.21 - - @difizen/libro-common@0.1.21 - - @difizen/libro-shared-model@0.1.21 - - @difizen/libro-virtualized@0.1.21 - -## 0.1.20 - -### Patch Changes - -- f3924d3: 1.fix search scroll on large cell 2.add libroModel in VirtualizedManager -- Updated dependencies [f3924d3] - - @difizen/libro-code-editor@0.1.20 - - @difizen/libro-common@0.1.20 - - @difizen/libro-shared-model@0.1.20 - - @difizen/libro-virtualized@0.1.20 - -## 0.1.19 - -### Patch Changes - -- fe3ee51: fix:poll kernels when serverManager ready -- Updated dependencies [fe3ee51] - - @difizen/libro-code-editor@0.1.19 - - @difizen/libro-common@0.1.19 - - @difizen/libro-shared-model@0.1.19 - - @difizen/libro-virtualized@0.1.19 - -## 0.1.18 - -### Patch Changes - -- f7c6839: File uploads can now be triggered by right-clicking on the file tree. -- 0f9e69d: Lab supports saving of all code files. -- 0f9e69d: More user-friendly prompt cell setting operation. -- Updated dependencies [f7c6839] -- Updated dependencies [0f9e69d] -- Updated dependencies [0f9e69d] - - @difizen/libro-shared-model@0.1.18 - - @difizen/libro-code-editor@0.1.18 - - @difizen/libro-virtualized@0.1.18 - - @difizen/libro-common@0.1.18 - -## 0.1.17 - -### Patch Changes - -- b159277: insert and execute output in a cell -- 9ff1bf9: Support file download. -- Updated dependencies [b159277] -- Updated dependencies [9ff1bf9] - - @difizen/libro-code-editor@0.1.17 - - @difizen/libro-common@0.1.17 - - @difizen/libro-shared-model@0.1.17 - - @difizen/libro-virtualized@0.1.17 - -## 0.1.16 - -### Patch Changes - -- 7d1edf3: Fix: Make Terminals opened from left panel same as the one you created, instead of creating a new terminal view. -- 90f6f8e: Fix: Cancel observing outputs height change' -- Updated dependencies [7d1edf3] -- Updated dependencies [90f6f8e] - - @difizen/libro-code-editor@0.1.16 - - @difizen/libro-common@0.1.16 - - @difizen/libro-shared-model@0.1.16 - - @difizen/libro-virtualized@0.1.16 - -## 0.1.15 - -### Patch Changes - -- 1b88a16: Feature: Better Prompt cell! Now based on better prompt magic support, you can use prompt cells to chat directly with OpenAI models. And you can put chats in context and create exciting workflows. -- Updated dependencies [1b88a16] - - @difizen/libro-shared-model@0.1.15 - - @difizen/libro-code-editor@0.1.15 - - @difizen/libro-virtualized@0.1.15 - - @difizen/libro-common@0.1.15 - -## 0.1.14 - -### Patch Changes - -- 0b882d3: 1. prompt cell adapt to the api of libro-server 2.fix the editor in CodeEditorView is undefined -- Updated dependencies [0b882d3] - - @difizen/libro-code-editor@0.1.14 - - @difizen/libro-common@0.1.14 - - @difizen/libro-shared-model@0.1.14 - - @difizen/libro-virtualized@0.1.14 - -## 0.1.13 - -### Patch Changes - -- 262ba79: 1. fix the editor in CodeEditorView is undefined -- Updated dependencies [262ba79] - - @difizen/libro-code-editor@0.1.13 - - @difizen/libro-common@0.1.13 - - @difizen/libro-shared-model@0.1.13 - - @difizen/libro-virtualized@0.1.13 - -## 0.1.12 - -### Patch Changes - -- bf45fa2: 1. fix:close the open tab when delete the file 2. stop propagation when focus cell right toolbar -- Updated dependencies [bf45fa2] - - @difizen/libro-code-editor@0.1.12 - - @difizen/libro-common@0.1.12 - - @difizen/libro-shared-model@0.1.12 - - @difizen/libro-virtualized@0.1.12 - -## 0.1.11 - -### Patch Changes - -- 236634d: 1.libro keybind not work when switching tabs - 2.auto focus when input file name. - 3.editor resize when CodeEditorViewer resize - 4.add file size warning - 5.add UI for file formats not supported for viewing - 6.file name error when select other format -- Updated dependencies [236634d] - - @difizen/libro-code-editor@0.1.11 - - @difizen/libro-common@0.1.11 - - @difizen/libro-shared-model@0.1.11 - - @difizen/libro-virtualized@0.1.11 - -## 0.1.10 - -### Patch Changes - -- ccdd12d: 1. add remove action in file tree menu -- Updated dependencies [ccdd12d] - - @difizen/libro-code-editor@0.1.10 - - @difizen/libro-common@0.1.10 - - @difizen/libro-shared-model@0.1.10 - - @difizen/libro-virtualized@0.1.10 - -## 0.1.9 - -### Patch Changes - -- ad803e2: 1. use codeEditorViewer as the last resort file viewer. 2. fix terminal -- Updated dependencies [ad803e2] - - @difizen/libro-code-editor@0.1.9 - - @difizen/libro-common@0.1.9 - - @difizen/libro-shared-model@0.1.9 - - @difizen/libro-virtualized@0.1.9 - -## 0.1.8 - -### Patch Changes - -- 1. Support json and other file formats. - 2. Dynamic shortcut keys and menus when switching tabs. -- Updated dependencies - - @difizen/libro-code-editor@0.1.8 - - @difizen/libro-common@0.1.8 - - @difizen/libro-shared-model@0.1.8 - - @difizen/libro-virtualized@0.1.8 - -## 0.1.7 - -### Patch Changes - -- Clean lab modules. -- Updated dependencies - - @difizen/libro-code-editor@0.1.7 - - @difizen/libro-common@0.1.7 - - @difizen/libro-shared-model@0.1.7 - - @difizen/libro-virtualized@0.1.7 - -## 0.1.6 - -### Patch Changes - -- Support code file editing. -- Updated dependencies - - @difizen/libro-code-editor@0.1.6 - - @difizen/libro-common@0.1.6 - - @difizen/libro-shared-model@0.1.6 - - @difizen/libro-virtualized@0.1.6 - -## 0.1.5 - -### Patch Changes - -- 1. Support image preview. - 2. Export the definition and implementation of the libro lab module. -- Updated dependencies - - @difizen/libro-code-editor@0.1.5 - - @difizen/libro-common@0.1.5 - - @difizen/libro-shared-model@0.1.5 - - @difizen/libro-virtualized@0.1.5 - -## 0.1.4 - -### Patch Changes - -- Fix issues with lsp and virtual list. -- Updated dependencies - - @difizen/libro-code-editor@0.1.4 - - @difizen/libro-virtualized@0.1.4 - - @difizen/libro-common@0.1.4 - - @difizen/libro-shared-model@0.1.4 - -## 0.1.3 - -### Patch Changes - -- Fix the content format issue of prompt cell -- Updated dependencies - - @difizen/libro-code-editor@0.1.3 - - @difizen/libro-common@0.1.3 - - @difizen/libro-shared-model@0.1.3 - - @difizen/libro-virtualized@0.1.3 - -## 0.1.2 - -### Patch Changes - -- 1. Support monaco editor, code cell is migrated to monaco editor by default. - 2. Support virtual lists to improve performance. - 3. libro lab can now use terminal. -- Updated dependencies - - @difizen/libro-code-editor@0.1.2 - - @difizen/libro-common@0.1.2 - - @difizen/libro-shared-model@0.1.2 - - @difizen/libro-virtualized@0.1.2 - -## 0.1.1 - -### Patch Changes - -- 1. Prompt cell is now available 🎉. - 2. Better lab UI. -- Updated dependencies - - @difizen/libro-code-editor@0.1.1 - - @difizen/libro-common@0.1.1 - - @difizen/libro-shared-model@0.1.1 - -## 0.1.0 - -### Minor Changes - -- 1. All modules used to support the notebook editor. - 2. Support lab products. - -### Patch Changes - -- 127cb35: Initia version -- Updated dependencies [127cb35] -- Updated dependencies - - @difizen/libro-code-editor@0.1.0 - - @difizen/libro-common@0.1.0 - - @difizen/libro-shared-model@0.1.0 - -## 0.0.2-alpha.0 - -### Patch Changes - -- Initia version -- Updated dependencies - - @difizen/libro-code-editor@0.0.2-alpha.0 - - @difizen/libro-common@0.0.2-alpha.0 - - @difizen/libro-shared-model@0.0.2-alpha.0 diff --git a/web/packages/magent-flow/babel.config.json b/web/packages/magent-flow/babel.config.json deleted file mode 100644 index efd1224..0000000 --- a/web/packages/magent-flow/babel.config.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - [ - "@babel/preset-react", - { - "runtime": "automatic" - } - ], - "@babel/preset-typescript" - ], - "plugins": [ - ["@babel/plugin-proposal-decorators", { "legacy": true }], - ["@babel/plugin-transform-flow-strip-types", { "allowDeclareFields": true }], - ["@babel/plugin-transform-private-methods", { "loose": true }], - ["@babel/plugin-transform-private-property-in-object", { "loose": true }], - ["@babel/plugin-transform-class-properties", { "loose": true }], - "babel-plugin-parameter-decorator" - ] -} diff --git a/web/ui/src/views/chat/index.ts b/web/ui/src/views/chat/index.ts deleted file mode 100644 index 7f1359f..0000000 --- a/web/ui/src/views/chat/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './module.js'; -export * from './chat-manager.js'; -export * from './message-manager.js'; -export * from './view.js'; -export * from './chat-message.js'; -export * from './protocol.js'; From b85a6b12755f8c4179897ab56b2579c1db2498ab Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Wed, 28 Aug 2024 01:57:10 +0800 Subject: [PATCH 11/78] chore: upgrade certifi to version 2024.07.04 or later --- api/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/requirements.txt b/api/requirements.txt index 219e24e..95ec0db 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -16,7 +16,7 @@ anyio==4.4.0 # via httpx # via starlette # via watchfiles -certifi==2024.6.2 +certifi==2024.7.4 # via httpcore # via httpx click==8.1.7 From 2c36df776d9f64500969617e3e310ea2338e9deb Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Wed, 28 Aug 2024 20:24:24 +0800 Subject: [PATCH 12/78] feat(ui): agent creation --- .../src/magent_ui/routers/agents/router.py | 15 +- .../components/agent-type-selector/index.less | 44 ++++ .../components/agent-type-selector/index.tsx | 49 ++++ .../components/agent-type-selector/rag.svg | 1 + .../components/agent-type-selector/react.svg | 1 + .../agent-type-selector/workflow.svg | 1 + .../src/components/avatar-upload/index.less | 7 + .../ui/src/modules/agent/agent-manager.ts | 23 +- web-apps/ui/src/modules/agent/agent-model.ts | 2 +- web-apps/ui/src/modules/agent/protocol.ts | 17 +- web-apps/ui/src/modules/model/index.ts | 2 +- web-apps/ui/src/modules/model/llm-manager.ts | 52 ++-- web-apps/ui/src/modules/model/llm-model.ts | 108 ++++++-- .../src/modules/model/llm-provider-manager.ts | 41 +++ .../ui/src/modules/model/model-icon/index.tsx | 6 +- .../modules/model/model-selector/index.less | 61 +++++ .../modules/model/model-selector/index.tsx | 233 ++++++++++++++++++ web-apps/ui/src/modules/model/module.ts | 30 ++- web-apps/ui/src/modules/model/protocol.ts | 21 +- .../components/model-selector/index.tsx | 27 +- web-apps/ui/src/views/agent-config/view.tsx | 18 +- web-apps/ui/src/views/agents/modal/create.tsx | 103 ++++++-- 22 files changed, 754 insertions(+), 108 deletions(-) create mode 100644 web-apps/ui/src/components/agent-type-selector/index.less create mode 100644 web-apps/ui/src/components/agent-type-selector/index.tsx create mode 100644 web-apps/ui/src/components/agent-type-selector/rag.svg create mode 100644 web-apps/ui/src/components/agent-type-selector/react.svg create mode 100644 web-apps/ui/src/components/agent-type-selector/workflow.svg create mode 100644 web-apps/ui/src/modules/model/llm-provider-manager.ts create mode 100644 web-apps/ui/src/modules/model/model-selector/index.less create mode 100644 web-apps/ui/src/modules/model/model-selector/index.tsx diff --git a/packages/magent-ui/src/magent_ui/routers/agents/router.py b/packages/magent-ui/src/magent_ui/routers/agents/router.py index 3647360..751d080 100644 --- a/packages/magent-ui/src/magent_ui/routers/agents/router.py +++ b/packages/magent-ui/src/magent_ui/routers/agents/router.py @@ -4,7 +4,10 @@ from typing import AsyncIterable, List from fastapi import APIRouter from agentuniverse_product.service.agent_service.agent_service import AgentService +from agentuniverse_product.service.workflow_service.workflow_service import WorkflowService from agentuniverse_product.service.model.agent_dto import AgentDTO +from agentuniverse_product.service.model.workflow_dto import WorkflowDTO +from agentuniverse_product.service.model.planner_dto import PlannerDTO from pydantic import BaseModel from sse_starlette import EventSourceResponse, ServerSentEvent @@ -26,10 +29,20 @@ async def get_agent_detail(agent_id): async def update_agent(agent_id, agent: AgentDTO): return AgentService.update_agent(agent) -@router.post("/agents", response_model=AgentDTO) +@router.post("/agents", response_model=str) async def create_agent(agent: AgentDTO): return AgentService.create_agent(agent) + +@router.post("/agents/workflow", response_model=str) +async def create_workflow_agent(agent: AgentDTO): + workflow_id = f"{agent.id}_workflow" + workflow_name = f"{agent.nickname}_workflow" + workflow = WorkflowDTO(id=workflow_id, name=workflow_name) + WorkflowService.create_workflow(workflow) + agent.planner = PlannerDTO(id='workflow_planner', workflow_id=workflow_id) + return AgentService.create_agent(agent) + class MessageSenderType(enum.Enum): AI = "ai" HUMAN = "human" diff --git a/web-apps/ui/src/components/agent-type-selector/index.less b/web-apps/ui/src/components/agent-type-selector/index.less new file mode 100644 index 0000000..92ae65d --- /dev/null +++ b/web-apps/ui/src/components/agent-type-selector/index.less @@ -0,0 +1,44 @@ +.magent-agent-type-selector { + .ant-radio-button-wrapper { + height: auto; + border-radius: 6px; + border: 1px solid var(--mana-ant-color-border-secondary); + + :nth-child(2) { + display: flex; + } + + &::before { + display: none; + } + } + + .ant-radio-button-wrapper-checked { + border-color: #1677ff; + } + + .ant-radio-button-wrapper + .ant-radio-button-wrapper { + margin-left: 24px; + } + + // .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) { + // &::before { + // display: none; + // } + // } + + &-label { + display: flex; + align-items: center; + flex-direction: column; + width: 64px; + padding: 20px 12px 12px; + justify-content: space-between; + height: 100px; + + .ant-avatar { + height: auto; + width: auto; + } + } +} diff --git a/web-apps/ui/src/components/agent-type-selector/index.tsx b/web-apps/ui/src/components/agent-type-selector/index.tsx new file mode 100644 index 0000000..f2ce7b3 --- /dev/null +++ b/web-apps/ui/src/components/agent-type-selector/index.tsx @@ -0,0 +1,49 @@ +import type { RadioGroupProps } from 'antd'; +import { Avatar } from 'antd'; +import { Radio } from 'antd'; + +import ragIcon from './rag.svg'; +import reactIcon from './react.svg'; +import workflowIcon from './workflow.svg'; +import './index.less'; + +export const AgentTypeSelector = (props: RadioGroupProps) => { + const options = [ + { + label: ( +
+ + RAG +
+ ), + value: 'rag_planner', + }, + { + label: ( +
+ + ReAct +
+ ), + value: 'react_planner', + }, + { + label: ( +
+ + Workflow +
+ ), + value: 'workflow_planner', + }, + ]; + + return ( + + ); +}; diff --git a/web-apps/ui/src/components/agent-type-selector/rag.svg b/web-apps/ui/src/components/agent-type-selector/rag.svg new file mode 100644 index 0000000..be6c454 --- /dev/null +++ b/web-apps/ui/src/components/agent-type-selector/rag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/components/agent-type-selector/react.svg b/web-apps/ui/src/components/agent-type-selector/react.svg new file mode 100644 index 0000000..96b430d --- /dev/null +++ b/web-apps/ui/src/components/agent-type-selector/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/components/agent-type-selector/workflow.svg b/web-apps/ui/src/components/agent-type-selector/workflow.svg new file mode 100644 index 0000000..e8011fd --- /dev/null +++ b/web-apps/ui/src/components/agent-type-selector/workflow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/components/avatar-upload/index.less b/web-apps/ui/src/components/avatar-upload/index.less index cfda261..12d6117 100644 --- a/web-apps/ui/src/components/avatar-upload/index.less +++ b/web-apps/ui/src/components/avatar-upload/index.less @@ -45,6 +45,13 @@ background-color: var(--mana-ant-control-item-bg-active-disabled); } + .ant-upload { + .ant-avatar { + width: auto; + height: auto; + } + } + .ant-upload.ant-upload-select { &:not(.ant-upload-disabled) { border-color: var(--mana-ant-color-primary); diff --git a/web-apps/ui/src/modules/agent/agent-manager.ts b/web-apps/ui/src/modules/agent/agent-manager.ts index b96fa3f..dc6ffd3 100644 --- a/web-apps/ui/src/modules/agent/agent-manager.ts +++ b/web-apps/ui/src/modules/agent/agent-manager.ts @@ -3,7 +3,11 @@ import { inject, singleton } from '@difizen/mana-app'; import { AxiosClient } from '../axios-client/protocol.js'; import { AgentModelFactory } from './protocol.js'; -import type { AgentModel, AgentModelOption } from './protocol.js'; +import type { + AgentModel, + AgentModelOption, + AgentModelCreateOption, +} from './protocol.js'; @singleton() export class AgentManager { @@ -29,4 +33,21 @@ export class AgentManager { this.cache.set(bot.id, bot); return bot; }; + + create = async (option: AgentModelCreateOption) => { + let res; + if (option.planner.id === 'workflow_planner') { + res = await this.doCreateWorkflowAgent(option); + } else { + res = await this.doCreateNormalAgent(option); + } + return res; + }; + + protected doCreateNormalAgent = async (option: AgentModelCreateOption) => { + return await this.axios.post(`/api/v1/agents`, option); + }; + protected doCreateWorkflowAgent = async (option: AgentModelCreateOption) => { + return await this.axios.post(`/api/v1/agents/workflow`, option); + }; } diff --git a/web-apps/ui/src/modules/agent/agent-model.ts b/web-apps/ui/src/modules/agent/agent-model.ts index c537555..6311e87 100644 --- a/web-apps/ui/src/modules/agent/agent-model.ts +++ b/web-apps/ui/src/modules/agent/agent-model.ts @@ -111,7 +111,7 @@ export class AgentModel extends AsyncModel { this.description = option.description; this.prompt = option.prompt ? new Prompt(option.prompt) : undefined; - this.llm = option.llm ? this.llmManager.getOrCreate(option.llm) : option.llm; + this.llm = option.llm ? this.llmManager.factory(option.llm) : option.llm; this.memory = option.memory ?? ''; this.planner = option.planner; this.knowledge = option.knowledge; diff --git a/web-apps/ui/src/modules/agent/protocol.ts b/web-apps/ui/src/modules/agent/protocol.ts index b5759b2..9cd1e57 100644 --- a/web-apps/ui/src/modules/agent/protocol.ts +++ b/web-apps/ui/src/modules/agent/protocol.ts @@ -1,5 +1,6 @@ import { Syringe } from '@difizen/mana-app'; +import type { LLMMeta } from '../model/protocol.js'; import type { ToolModelOption } from '../tool/protocol.js'; import type { AgentConfig } from './agent-config.js'; @@ -17,12 +18,6 @@ export interface PromptMeta { target: string; instruction: string; } -export interface LLMMeta { - id: string; - nickname: string; - temperature: number; - model_name: string[]; -} export interface AgentConfigOption { opening_speech?: string; @@ -92,6 +87,16 @@ export const AgentModelFactory = Syringe.defineToken('AgentModelFactory', { multiple: false, }); +export interface AgentModelCreateOption { + description?: string; + avatar?: string; + nickname?: string; + planner: Partial; + llm?: Partial; + prompt?: Partial; + id: string; +} + export const AgentModelType = { isOption(data?: Record): data is AgentModelOption { return !!(data && 'id' in data); diff --git a/web-apps/ui/src/modules/model/index.ts b/web-apps/ui/src/modules/model/index.ts index bdc0d5b..178b1cb 100644 --- a/web-apps/ui/src/modules/model/index.ts +++ b/web-apps/ui/src/modules/model/index.ts @@ -1,4 +1,4 @@ export * from './module.js'; -export * from './llm-manager.js'; +export * from './llm-provider-manager.js'; export * from './llm-model.js'; export * from './protocol.js'; diff --git a/web-apps/ui/src/modules/model/llm-manager.ts b/web-apps/ui/src/modules/model/llm-manager.ts index cf045fc..6beae27 100644 --- a/web-apps/ui/src/modules/model/llm-manager.ts +++ b/web-apps/ui/src/modules/model/llm-manager.ts @@ -1,47 +1,29 @@ -import { inject, prop, singleton } from '@difizen/mana-app'; +import { inject, singleton } from '@difizen/mana-app'; -import { AxiosClient } from '../axios-client/protocol.js'; - -import type { LLMModel } from './llm-model.js'; -import type { ModelMeta } from './protocol.js'; +import type { LLMModel, LLMProvider } from './llm-model.js'; +import { LLMProviderManager } from './llm-provider-manager.js'; import { LLMModelFactory } from './protocol.js'; @singleton() export class LLMManager { - protected cache: Map = new Map(); + protected cache: Map = new Map(); @inject(LLMModelFactory) factory: LLMModelFactory; - @inject(AxiosClient) axios: AxiosClient; - - @prop() - models: LLMModel[] = []; + @inject(LLMProviderManager) protected providerManager: LLMProviderManager; - defaultModel?: LLMModel; - - protected getModelsMeta = async () => { - const defaultValue: ModelMeta[] = []; - const res = await this.axios.get(`/api/v1/llms`); - if (res.status === 200) { - return res.data; + get default(): LLMModel | undefined { + const llm = this.providerManager.models.find((item) => item.models.length > 0); + if (!llm) { + return undefined; } - return defaultValue; - }; - - updateModels = async () => { - const metas = await this.getModelsMeta(); - this.models = metas.map((item) => this.getOrCreate(item)); - if (this.models.length > 0) { - const defaultLLM = this.models[0]; - this.defaultModel = defaultLLM; + const name = llm.models[0]; + const meta = llm.toSingleMeta(name); + if (!meta) { + return undefined; } - }; + return this.factory(meta); + } - getOrCreate = (option: ModelMeta): LLMModel => { - const exist = this.cache.get(option.id); - if (exist) { - return exist; - } - const llm = this.factory(option); - this.cache.set(llm.id, llm); - return llm; + updateFromProvider = () => { + return this.providerManager.updateProviders(); }; } diff --git a/web-apps/ui/src/modules/model/llm-model.ts b/web-apps/ui/src/modules/model/llm-model.ts index 849346b..5d0d1df 100644 --- a/web-apps/ui/src/modules/model/llm-model.ts +++ b/web-apps/ui/src/modules/model/llm-model.ts @@ -1,38 +1,57 @@ import { inject, prop, transient } from '@difizen/mana-app'; -import { LLMModelOption, type ModelMeta } from './protocol.js'; +import type { LLMProviderMeta } from './protocol.js'; +import { LLMProviderOption } from './protocol.js'; +import { LLMModelOption, type LLMMeta } from './protocol.js'; @transient() -export class LLMModel { +export class LLMProvider implements LLMProviderMeta { id: string; - name: string; - models: string[] = []; + + @prop() + nickname: string; + + @prop() + model_name: string[] = []; + + get name(): string { + return this.nickname; + } + set name(v: string) { + this.nickname = v; + } + + get models(): string[] { + return this.model_name; + } + set models(v: string[]) { + this.models = v; + } @prop() temperature: number; protected configStr: string; - constructor(@inject(LLMModelOption) meta: ModelMeta) { + constructor(@inject(LLMProviderOption) meta: LLMProviderMeta) { this.id = meta.id; - this.name = meta.nickname; - this.models = meta.model_name; + this.nickname = meta.nickname; + this.model_name = meta.model_name; } - toSingleMeta = (name: string): ModelMeta | undefined => { + toSingleMeta = (name: string): LLMMeta | undefined => { if (!this.models.includes(name)) { return undefined; } const meta = this.toMeta(); - meta.model_name = [name]; - return meta; + return { ...meta, model_name: [name] }; }; - toMeta = (): ModelMeta => { - const meta: ModelMeta = { + toMeta = (): LLMProviderMeta => { + const meta: LLMProviderMeta = { id: this.id, - nickname: this.name, - model_name: this.models, + nickname: this.nickname, + model_name: this.model_name, temperature: this.temperature, }; return meta; @@ -42,3 +61,64 @@ export class LLMModel { return this.models.map(this.toSingleMeta); }; } + +@transient() +export class LLMModel implements LLMMeta { + id: string; + + @prop() + nickname: string; + + @prop() + model_name: [string]; + + get name(): string { + return this.nickname; + } + set name(v: string) { + this.nickname = v; + } + + get models(): string[] { + return this.model_name; + } + set models(v: string[]) { + this.models = v; + } + + @prop() + temperature: number; + + protected configStr: string; + + constructor(@inject(LLMModelOption) meta: LLMMeta) { + this.id = meta.id; + this.nickname = meta.nickname; + this.model_name = meta.model_name; + } + + updateMeta(meta: LLMMeta) { + if (this.id !== meta.id) { + this.id = meta.id; + } + if (this.nickname !== meta.nickname) { + this.nickname = meta.nickname; + } + if (this.temperature !== meta.temperature) { + this.temperature = meta.temperature; + } + if (this.model_name.join(',') !== meta.model_name.join(',')) { + this.model_name = meta.model_name; + } + } + + toMeta = (): LLMMeta => { + const meta: LLMMeta = { + id: this.id, + nickname: this.nickname, + model_name: this.model_name, + temperature: this.temperature, + }; + return meta; + }; +} diff --git a/web-apps/ui/src/modules/model/llm-provider-manager.ts b/web-apps/ui/src/modules/model/llm-provider-manager.ts new file mode 100644 index 0000000..c993b8a --- /dev/null +++ b/web-apps/ui/src/modules/model/llm-provider-manager.ts @@ -0,0 +1,41 @@ +import { inject, prop, singleton } from '@difizen/mana-app'; + +import { AxiosClient } from '../axios-client/protocol.js'; + +import type { LLMProvider } from './llm-model.js'; +import type { LLMMeta, LLMProviderMeta } from './protocol.js'; +import { LLMProviderFactory } from './protocol.js'; + +@singleton() +export class LLMProviderManager { + protected cache: Map = new Map(); + @inject(LLMProviderFactory) factory: LLMProviderFactory; + @inject(AxiosClient) axios: AxiosClient; + + @prop() + models: LLMProvider[] = []; + + protected getProviderssMeta = async () => { + const defaultValue: LLMMeta[] = []; + const res = await this.axios.get(`/api/v1/llms`); + if (res.status === 200) { + return res.data; + } + return defaultValue; + }; + + updateProviders = async () => { + const metas = await this.getProviderssMeta(); + this.models = metas.map((item) => this.getOrCreate(item)); + }; + + getOrCreate = (option: LLMProviderMeta): LLMProvider => { + const exist = this.cache.get(option.id); + if (exist) { + return exist; + } + const provider = this.factory(option); + this.cache.set(provider.id, provider); + return provider; + }; +} diff --git a/web-apps/ui/src/modules/model/model-icon/index.tsx b/web-apps/ui/src/modules/model/model-icon/index.tsx index 5532dfe..2b64cdb 100644 --- a/web-apps/ui/src/modules/model/model-icon/index.tsx +++ b/web-apps/ui/src/modules/model/model-icon/index.tsx @@ -1,6 +1,6 @@ import { lazy, Suspense } from 'react'; -import type { ModelMeta } from '@/modules/model/protocol.js'; +import type { LLMMeta } from '@/modules/model/protocol.js'; const LazyIcon = (props: { loader: () => Promise }) => { const Component = lazy(async () => { @@ -30,7 +30,7 @@ export const DefaultLLMIcon = () => { ); }; -const match = (data: ModelMeta, name: string): boolean => { +const match = (data: LLMMeta, name: string): boolean => { if ( data.id.toLowerCase().includes(name) || data.nickname.toLowerCase().includes(name) || @@ -41,7 +41,7 @@ const match = (data: ModelMeta, name: string): boolean => { return false; }; -export const LLMIcon = (props: { data: ModelMeta }) => { +export const LLMIcon = (props: { data: LLMMeta }) => { const { data } = props; if (match(data, 'qwen')) { return import('./qwen.svg')} />; diff --git a/web-apps/ui/src/modules/model/model-selector/index.less b/web-apps/ui/src/modules/model/model-selector/index.less new file mode 100644 index 0000000..c412136 --- /dev/null +++ b/web-apps/ui/src/modules/model/model-selector/index.less @@ -0,0 +1,61 @@ +.agent-config-model-selector { + display: flex; + + &-btn { + border: none; + background: none; + box-shadow: none; + padding: 1px 6px 1px 12px; + min-height: 32px; + + .ant-btn-icon { + .anticon { + font-size: 10px; + } + } + } + + > .ant-btn-default:not(:disabled):hover { + background-color: var(--mana-activityBar-background); + color: unset; + } + + &-option { + display: flex; + align-items: center; + min-height: 16px; + + &-icon { + display: inline-block; + } + + &-series { + margin-left: 4px; + color: var(--mana-text-secondary); + column-gap: 4px; + display: flex; + font-size: 12px; + } + + &-label { + margin-left: 4px; + // color: var(--mana-text-secondary); + column-gap: 4px; + display: flex; + font-size: 12px; + } + } + + &-popover { + width: 480px; + + .ant-popover-inner { + padding: 16px; + } + + .ant-popover-title { + font-size: 16px; + font-weight: 500; + } + } +} diff --git a/web-apps/ui/src/modules/model/model-selector/index.tsx b/web-apps/ui/src/modules/model/model-selector/index.tsx new file mode 100644 index 0000000..12fc207 --- /dev/null +++ b/web-apps/ui/src/modules/model/model-selector/index.tsx @@ -0,0 +1,233 @@ +import { CaretDownOutlined } from '@ant-design/icons'; +import { useInject, useObserve } from '@difizen/mana-app'; +import type { SliderSingleProps } from 'antd'; +import { Button, Form, Select, Popover, Avatar, Slider } from 'antd'; +import type { FC } from 'react'; +import { useState } from 'react'; +import { forwardRef, useEffect } from 'react'; + +import { LLMModel } from '@/modules/model/llm-model.js'; +import { LLMProviderManager } from '@/modules/model/llm-provider-manager.js'; +import { LLMIcon } from '@/modules/model/model-icon/index.js'; +import type { LLMMeta } from '@/modules/model/protocol.js'; + +import './index.less'; + +const clsPrefix = 'agent-config-model-selector'; + +const ModelSelectorOption = (props: { model: LLMMeta; flat?: boolean }) => { + const { model, flat } = props; + return ( +
+ } + /> + {flat && {model.nickname}} + {model.model_name[0]} +
+ ); +}; + +const toKey = (model?: LLMMeta) => { + if (!model) { + return undefined; + } + return model.id + model.model_name[0]; +}; + +interface TemperatureSliderProps extends SliderSingleProps { + llm?: LLMMeta; + onConfigChange?: (v: LLMMeta) => void; +} +const TemperatureSlider: FC = ( + props: TemperatureSliderProps, +) => { + const llm = useObserve(props.llm); + const temperature = llm?.temperature; + return ( + { + if (llm) { + llm.temperature = v; + props.onConfigChange?.(llm); + } + }} + value={temperature === undefined ? 1 : temperature} + /> + ); +}; + +interface ModelSelectorProps { + value?: LLMMeta | LLMModel | string; + onChange?: (v?: LLMMeta) => void; + showConfig?: boolean; + popoverMode?: boolean; + onConfigChanged?: (v: LLMMeta) => void; +} + +export const ModelSelector = forwardRef( + function ModelSelectorComponent(props: ModelSelectorProps, ref) { + const { showConfig = true, popoverMode = true } = props; + const shouldShowConfig = popoverMode ? showConfig : false; + const modelProvider = useInject(LLMProviderManager); + const [stateValue, setStateValue] = useState(undefined); + + const models = modelProvider.models; + + const llms = models + .map((item) => item.toSingleMetas()) + .filter((item) => !!item) + .flat(); + + const toLLM = (v: undefined | LLMMeta | string): LLMMeta | undefined => { + if (v === undefined) { + return v; + } + if (typeof v === 'string') { + return llms.find((item) => toKey(item) === v); + } + return v; + }; + + const currentModel = toLLM(props.value) || stateValue; + + useEffect(() => { + modelProvider.updateProviders(); + }, [modelProvider]); + + if (!popoverMode) { + return ( + + ); + } + + return ( +
+ +
+ + + + {shouldShowConfig && ( + + { + props.onConfigChanged?.(v); + props.onChange?.(v); + }} + llm={currentModel} + /> + + )} +
+
+ } + > + + + + ); + }, +); diff --git a/web-apps/ui/src/modules/model/module.ts b/web-apps/ui/src/modules/model/module.ts index 50f8260..4ae661f 100644 --- a/web-apps/ui/src/modules/model/module.ts +++ b/web-apps/ui/src/modules/model/module.ts @@ -1,20 +1,36 @@ import { ManaModule } from '@difizen/mana-app'; import { LLMManager } from './llm-manager.js'; -import { LLMModel } from './llm-model.js'; -import type { ModelMeta } from './protocol.js'; +import { LLMModel, LLMProvider } from './llm-model.js'; +import { LLMProviderManager } from './llm-provider-manager.js'; +import type { LLMMeta, LLMProviderMeta } from './protocol.js'; +import { LLMProviderFactory, LLMProviderOption } from './protocol.js'; import { LLMModelOption } from './protocol.js'; import { LLMModelFactory } from './protocol.js'; -export const ModelModule = ManaModule.create() - .register(LLMModel, LLMManager) - .register({ +export const ModelModule = ManaModule.create().register( + LLMProvider, + LLMProviderManager, + LLMModel, + LLMManager, + { token: LLMModelFactory, useFactory: (ctx) => { - return (meta: ModelMeta) => { + return (meta: LLMMeta) => { const child = ctx.container.createChild(); child.register({ token: LLMModelOption, useValue: meta }); return child.get(LLMModel); }; }, - }); + }, + { + token: LLMProviderFactory, + useFactory: (ctx) => { + return (meta: LLMProviderMeta) => { + const child = ctx.container.createChild(); + child.register({ token: LLMProviderOption, useValue: meta }); + return child.get(LLMProvider); + }; + }, + }, +); diff --git a/web-apps/ui/src/modules/model/protocol.ts b/web-apps/ui/src/modules/model/protocol.ts index 0f74147..c25e145 100644 --- a/web-apps/ui/src/modules/model/protocol.ts +++ b/web-apps/ui/src/modules/model/protocol.ts @@ -1,17 +1,30 @@ import { Syringe } from '@difizen/mana-app'; -import type { LLMModel } from './llm-model.js'; +import type { LLMModel, LLMProvider } from './llm-model.js'; -export interface ModelMeta { +export interface LLMMeta { id: string; nickname: string; temperature: number; - model_name: string[]; + model_name: [string]; } -export type LLMModelFactory = (option: ModelMeta) => LLMModel; +export type LLMModelFactory = (option: LLMMeta) => LLMModel; export const LLMModelFactory = Syringe.defineToken('LLMModelFactory'); export const LLMModelOption = Syringe.defineToken('LLMModelOption', { multiple: false, }); + +export interface LLMProviderMeta { + id: string; + nickname: string; + temperature: number; + model_name: string[]; +} +export type LLMProviderFactory = (option: LLMProviderMeta) => LLMProvider; +export const LLMProviderFactory = Syringe.defineToken('LLMProviderFactory'); + +export const LLMProviderOption = Syringe.defineToken('LLMProviderOption', { + multiple: false, +}); diff --git a/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx b/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx index 6869f86..5c0605c 100644 --- a/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx +++ b/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx @@ -5,10 +5,10 @@ import { Button, Form, Select, Popover, Avatar, Slider } from 'antd'; import type { FC } from 'react'; import { forwardRef, useEffect } from 'react'; -import { LLMManager } from '@/modules/model/llm-manager.js'; -import type { LLMModel } from '@/modules/model/llm-model.js'; +import type { LLMProvider } from '@/modules/model/llm-model.js'; +import { LLMProviderManager } from '@/modules/model/llm-provider-manager.js'; import { LLMIcon } from '@/modules/model/model-icon/index.js'; -import type { ModelMeta } from '@/modules/model/protocol.js'; +import type { LLMMeta } from '@/modules/model/protocol.js'; import type { AgentConfigView } from '../../view.js'; @@ -16,7 +16,7 @@ import './index.less'; const clsPrefix = 'agent-config-model-selector'; -const ModelSelectorOption = (props: { model: ModelMeta; flat?: boolean }) => { +const ModelSelectorOption = (props: { model: LLMMeta; flat?: boolean }) => { const { model, flat } = props; return (
@@ -31,7 +31,7 @@ const ModelSelectorOption = (props: { model: ModelMeta; flat?: boolean }) => { ); }; -const toKey = (model?: ModelMeta) => { +const toKey = (model?: LLMMeta) => { if (!model) { return undefined; } @@ -39,7 +39,7 @@ const toKey = (model?: ModelMeta) => { }; interface TemperatureSliderProps extends SliderSingleProps { - llm?: LLMModel; + llm?: LLMProvider; } const TemperatureSlider: FC = ( props: TemperatureSliderProps, @@ -65,24 +65,23 @@ const TemperatureSlider: FC = ( export const ModelSelector = forwardRef( function ModelSelectorComponent(props, ref) { const instance = useInject(ViewInstance); - const modelManager = useInject(LLMManager); - // const defaultModel = modelManager.defaultModel; + const modelProviderManager = useInject(LLMProviderManager); const modelMeta = instance.agent?.llm; - const models = modelManager.models; + const models = modelProviderManager.models; const metaModels = models .map((item) => item.toSingleMetas()) .filter((item) => !!item) - .flat() as ModelMeta[]; + .flat() as LLMMeta[]; useEffect(() => { - modelManager.updateModels(); - }, [modelManager]); + modelProviderManager.updateProviders(); + }, [modelProviderManager]); const currentModel = metaModels.find( - (item) => modelMeta && toKey(item) === toKey(modelMeta.toMeta()), + (item) => modelMeta && toKey(item) === toKey(modelMeta), ); return ( @@ -101,7 +100,7 @@ export const ModelSelector = forwardRef( onSelect={(v) => { const llm = metaModels.find((i) => toKey(i) === v); if (instance.agent.llm && llm) { - instance.agent.llm = modelManager.getOrCreate(llm); + instance.agent.llm = modelProviderManager.getOrCreate(llm); } }} value={toKey(instance.agent.llm?.toMeta())} diff --git a/web-apps/ui/src/views/agent-config/view.tsx b/web-apps/ui/src/views/agent-config/view.tsx index eab0f4f..8af9859 100644 --- a/web-apps/ui/src/views/agent-config/view.tsx +++ b/web-apps/ui/src/views/agent-config/view.tsx @@ -16,14 +16,14 @@ import { forwardRef } from 'react'; import { AgentManager } from '@/modules/agent/agent-manager.js'; import type { AgentModel } from '@/modules/agent/protocol.js'; import { KnowledgeIcon } from '@/modules/knowledge/knowledge-icon.js'; +import { ModelSelector } from '@/modules/model/model-selector/index.js'; import { ToolIcon } from '@/modules/tool/tool-icon.js'; import { CharacterSetting } from './components/character-setting/index.js'; import { ConfigList } from './components/config-selector/index.js'; -import { ModelSelector } from './components/model-selector/index.js'; -import './index.less'; import { KnowledgeModal } from './knowledge-modal/modal.js'; import { ToolsModal } from './tools-modal/modal.js'; +import './index.less'; const viewId = 'magent-dev-config'; @@ -48,7 +48,19 @@ const AgentConfigViewComponent = forwardRef(
模型
- + { + if (meta) { + instance.agent.llm?.updateMeta(meta); + } + }} + onConfigChanged={(meta) => { + if (meta) { + instance.agent.llm?.updateMeta(meta); + } + }} + />
> = ( useEffect(() => { form - .validateFields({ validateOnly: true }) + .validateFields({ + validateOnly: true, + }) .then(() => setSubmittable(true)) .catch(() => setSubmittable(false)); }, [form, values]); return ( - ); @@ -51,9 +65,31 @@ const UploadButton = (props: { imageUrl?: string }) => { }; export const AgentModalComponent = (props: ModalItemProps) => { + const agentManager = useInject(AgentManager); + const llmManager = useInject(LLMManager); + const axios = useInject(AxiosClient); const { visible, close } = props; - const [form] = Form.useForm(); - const [idValue, setId] = useState(undefined); + const [form] = Form.useForm<{ + id: string; + plannerId: string; + avatar?: string; + nickname: string; + description?: string; + llm: LLMMeta; + }>(); + const idValue = Form.useWatch('id', form); + const plannerValue = Form.useWatch('plannerId', form); + useEffect(() => { + llmManager + .updateFromProvider() + .then(() => { + if (form.getFieldValue('llm') === undefined && llmManager.default) { + form.setFieldValue('llm', llmManager.default.toMeta()); + } + return; + }) + .catch(console.error); + }, [llmManager, form]); return ( ) => {
{ - const idChanged = changed.find( - (item) => - item.name instanceof Array && - item.name.length === 1 && - item.name[0] === 'id', - ); - if (idChanged && idChanged.validated) { - setId(idChanged.value); + onFinish={async (values) => { + const meta = { + id: values.id, + nickname: values.nickname, + avatar: values.avatar, + description: values.description, + prompt: { instruction: '', introduction: '', target: '' }, + planner: { id: values.plannerId, nickname: '' }, + llm: llmManager.default, + }; + const res = await agentManager.create(meta); + if (res.status === 200) { + close(); + history.push( + `/agent/${meta.id}/${meta.planner.id === 'workflow_planner' ? 'flow' : 'dev'}`, + ); } }} + onFinishFailed={console.error} + initialValues={{ plannerId: 'rag_planner' }} > - - + + + + ({ + // async validator(_, value) { + // const res = await axios.get(`/api/v1/llms`); + // }, + // }), + ]} + > + - + + {plannerValue !== 'workflow_planner' && ( + + + + )} Date: Wed, 28 Aug 2024 20:53:03 +0800 Subject: [PATCH 13/78] feat(ui): agent id validate --- .../src/magent_ui/routers/common/__init__.py | 0 .../src/magent_ui/routers/common/router.py | 16 +++++++++++++++ .../magent-ui/src/magent_ui/routers/main.py | 2 ++ .../ui/src/modules/axios-client/module.ts | 3 ++- .../ui/src/modules/axios-client/request.ts | 13 ++++++++++++ web-apps/ui/src/views/agents/modal/create.tsx | 20 ++++++++++++------- 6 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 packages/magent-ui/src/magent_ui/routers/common/__init__.py create mode 100644 packages/magent-ui/src/magent_ui/routers/common/router.py create mode 100644 web-apps/ui/src/modules/axios-client/request.ts diff --git a/packages/magent-ui/src/magent_ui/routers/common/__init__.py b/packages/magent-ui/src/magent_ui/routers/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/packages/magent-ui/src/magent_ui/routers/common/router.py b/packages/magent-ui/src/magent_ui/routers/common/router.py new file mode 100644 index 0000000..81d912f --- /dev/null +++ b/packages/magent-ui/src/magent_ui/routers/common/router.py @@ -0,0 +1,16 @@ +import asyncio +import enum +import json +from typing import AsyncIterable, List +from fastapi import APIRouter +import agentuniverse_product.service.util.product_util as util + +router = APIRouter() +common_router = router + + +@router.get("/common/is_id_unique", response_model=bool) +async def is_id_unique(id:str, type:str): + result = util.is_id_unique(id,type) + return result + diff --git a/packages/magent-ui/src/magent_ui/routers/main.py b/packages/magent-ui/src/magent_ui/routers/main.py index 3d59900..949f198 100644 --- a/packages/magent-ui/src/magent_ui/routers/main.py +++ b/packages/magent-ui/src/magent_ui/routers/main.py @@ -6,6 +6,7 @@ from magent_ui.routers.tools.router import tools_router from magent_ui.routers.resource.router import resource_router from magent_ui.routers.workflow.router import workflow_router +from magent_ui.routers.common.router import common_router api_router = APIRouter() @@ -16,3 +17,4 @@ api_router.include_router(tools_router, prefix="/v1", tags=["tool"]) api_router.include_router(resource_router, prefix="/v1", tags=["resource"]) api_router.include_router(workflow_router, prefix="/v1", tags=["workflow"]) +api_router.include_router(common_router, prefix="/v1", tags=["common"]) diff --git a/web-apps/ui/src/modules/axios-client/module.ts b/web-apps/ui/src/modules/axios-client/module.ts index e3b4e02..b9d0235 100644 --- a/web-apps/ui/src/modules/axios-client/module.ts +++ b/web-apps/ui/src/modules/axios-client/module.ts @@ -2,9 +2,10 @@ import { ManaModule, Syringe } from '@difizen/mana-app'; import { getContextClient } from './client.js'; import { AxiosClient } from './protocol.js'; +import { RequestHelper } from './request.js'; export const AxiosClientModule = ManaModule.create() - .register({ + .register(RequestHelper, { token: AxiosClient, useDynamic: getContextClient, lifecycle: Syringe.Lifecycle.singleton, diff --git a/web-apps/ui/src/modules/axios-client/request.ts b/web-apps/ui/src/modules/axios-client/request.ts new file mode 100644 index 0000000..f63bc8a --- /dev/null +++ b/web-apps/ui/src/modules/axios-client/request.ts @@ -0,0 +1,13 @@ +import { inject, singleton } from '@difizen/mana-app'; +import qs from 'query-string'; + +import { AxiosClient } from './protocol.js'; + +@singleton() +export class RequestHelper { + @inject(AxiosClient) axios: AxiosClient; + get(basePath: string, params: Record) { + const query = qs.stringify(params); + return this.axios.get(`${basePath}?${query}`); + } +} diff --git a/web-apps/ui/src/views/agents/modal/create.tsx b/web-apps/ui/src/views/agents/modal/create.tsx index 03739e1..03abb82 100644 --- a/web-apps/ui/src/views/agents/modal/create.tsx +++ b/web-apps/ui/src/views/agents/modal/create.tsx @@ -13,7 +13,7 @@ import { AgentTypeSelector } from '@/components/agent-type-selector/index.js'; import { AvatarUpload } from '@/components/avatar-upload/index.js'; import { AgentIcon } from '@/modules/agent/agent-icon.js'; import { AgentManager } from '@/modules/agent/agent-manager.js'; -import { AxiosClient } from '@/modules/axios-client/protocol.js'; +import { RequestHelper } from '@/modules/axios-client/request.js'; import { LLMManager } from '@/modules/model/llm-manager.js'; import { ModelSelector } from '@/modules/model/model-selector/index.js'; import type { LLMMeta } from '@/modules/model/protocol.js'; @@ -67,7 +67,7 @@ const UploadButton = (props: { imageUrl?: string }) => { export const AgentModalComponent = (props: ModalItemProps) => { const agentManager = useInject(AgentManager); const llmManager = useInject(LLMManager); - const axios = useInject(AxiosClient); + const req = useInject(RequestHelper); const { visible, close } = props; const [form] = Form.useForm<{ id: string; @@ -145,11 +145,17 @@ export const AgentModalComponent = (props: ModalItemProps) => { label="id" rules={[ { required: true }, - // ({ getFieldValue }) => ({ - // async validator(_, value) { - // const res = await axios.get(`/api/v1/llms`); - // }, - // }), + () => ({ + async validator(_, value) { + const res = await req.get(`/api/v1/common/is_id_unique`, { + id: value, + type: 'agent', + }); + if (res.status !== 200 || res.data === false) { + throw new Error(`${value} 已存在,请更换其他 id`); + } + }, + }), ]} > From cf9bc45865a78561cf2b2c723d6ba8c14e3e00e1 Mon Sep 17 00:00:00 2001 From: "xujianfeng.xjf" Date: Tue, 27 Aug 2024 20:06:29 +0800 Subject: [PATCH 14/78] feat: update node template in flow --- .../magent-flow/src/RefForm/index.tsx | 2 +- .../components/AIBasic/PromptEditor/index.tsx | 2 +- .../magent-flow/src/components/Flow/index.tsx | 2 + .../src/components/FlowWithPanel/index.tsx | 54 +++++------- .../src/components/Node/AgentNode/index.tsx | 69 +++++++++++++-- .../src/components/Node/EndNode/index.tsx | 85 +++++++++++++++---- .../src/components/Node/IfElseNode/index.tsx | 55 ++++++------ .../components/Node/KnowledgeNode/index.tsx | 18 +++- .../src/components/Node/LLMNode/index.tsx | 60 +++++++++---- .../src/components/Node/NodeWrapper/index.tsx | 5 +- .../src/components/ReferenceForm/index.tsx | 12 ++- .../src/components/ReferenceSelect/index.tsx | 25 +++--- .../src/components/VariableForm/index.tsx | 1 + .../magent-flow/src/interfaces/flow.ts | 42 +++++++-- .../magent-flow/src/stores/useFlowStore.ts | 7 +- .../src/components/ConditionForm/index.tsx | 56 ++++++++++++ .../src/components/Toolbar/index.tsx | 23 +++++ 17 files changed, 375 insertions(+), 143 deletions(-) create mode 100644 web/packages/magent-flow/src/components/ConditionForm/index.tsx create mode 100644 web/packages/magent-flow/src/components/Toolbar/index.tsx diff --git a/web-packages/magent-flow/src/RefForm/index.tsx b/web-packages/magent-flow/src/RefForm/index.tsx index 0dbe097..b7b66a1 100644 --- a/web-packages/magent-flow/src/RefForm/index.tsx +++ b/web-packages/magent-flow/src/RefForm/index.tsx @@ -15,7 +15,7 @@ interface CascaderOptions { */ const getCascaderOptions = (node: NodeDataType) => { const jsonSchema = node.config?.inputs?.jsonschema; - console.log('🚀 ~ getCascaderOptions ~ jsonSchema:', jsonSchema); + const options: CascaderOptions[] = [ { label: `${node.name}`, diff --git a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx index 8e97314..8c8061c 100644 --- a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx @@ -82,7 +82,7 @@ const PromptEditor: FC = ({ return ( -
+
{miniMap && } +
); diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx index 8ed246c..afd719d 100644 --- a/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx +++ b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx @@ -1,5 +1,4 @@ import yaml from 'js-yaml'; -import React from 'react'; import { EventEmitterContextProvider } from '@/context/event-emitter.js'; import type { NodeDataType } from '@/interfaces/flow.js'; @@ -19,9 +18,6 @@ const yamlContent = ` name: 开始节点 description: 工作流的起始节点,用于设定启动工作流需要的信息 type: start - position: - x: 100 - y: 100 data: outputs: - name: user_input @@ -41,19 +37,20 @@ const yamlContent = ` type: string value: type: reference - content: ['llm1', 'output'] # 通过nodeId + paramKey 定位引用变量 prompt: name: response type: string description: 输出内容 - value: '{{response}}' + value: + type: reference + content: '{{response}}' + outputs: + - name: output + type: string - id: 3 name: 大模型节点 description: 调用大语言模型,使用变量和提示词生成回复 type: llm - position: - x: 300 - y: 100 data: inputs: input_param: @@ -78,8 +75,11 @@ const yamlContent = ` name: temperature value: '0.7' - type: string - name: prompt - value: | + prompt: + type: string + value: + type: value + content: | 你是一位精通信息分析的ai助手。你的目标是使用中文结合查询的背景信息及你所拥有的知识回答用户提出的问题。 你需要遵守的规则是: 1. 必须使用中文结合查询的背景信息结合你所拥有的知识回答用户提出的问题。 @@ -91,20 +91,17 @@ const yamlContent = ` 7. 尽量多的使用数值类信息。 背景信息是: - {background} + {{background}} 开始! - 需要回答的问题是: {input} + 需要回答的问题是: {{input}} outputs: - type: string name: output - id: 4 - name: 知识库示例 + name: 知识库 description: type: knowledge - position: - x: 400 - y: 100 data: inputs: knowledge_param: @@ -125,7 +122,7 @@ const yamlContent = ` - name: output type: string - id: 5 - name: 谷歌搜索工具 + name: 工具 description: type: tool position: @@ -142,17 +139,14 @@ const yamlContent = ` name: input value: type: value - content: 'output' # 通过nodeId + paramKey 定位引用变量 + content: 'output' outputs: - name: output type: string - id: 6 - name: rag智能体 + name: Agent智能体 description: type: agent - position: - x: 600 - y: 100 data: inputs: agent_param: @@ -172,12 +166,9 @@ const yamlContent = ` name: 条件判断 description: type: ifelse - position: - x: 700 - y: 100 data: inputs: - branches: # 这一期这做一层,不包括 and or 还有我理解默认逻辑不展示在这块对吧,只在edge体现 + branches: - name: branch-1 conditions: - compare: equal @@ -189,16 +180,14 @@ const yamlContent = ` type: string # 只有 if 和 else,branch-1和branch-default value: type: reference - - `; export const NodeSchemaParser = (obj: Record) => { - obj.config = obj.data; - obj.icon = + obj['config'] = obj['data']; + obj['icon'] = 'https://mdn.alipayobjects.com/huamei_xbkogb/afts/img/A*PzmdRpvZz58AAAAAAAAAAAAADqarAQ/original'; - delete obj.data; + delete obj['data']; }; const nodeTypes = { @@ -216,7 +205,6 @@ export const FlowWithPanel = () => { (yaml_data as Record[]).forEach((item) => { NodeSchemaParser(item); }); - console.log('🚀 ~ yaml_data:', yaml_data); // const setNodes = useFlowStore((state) => state.setNodes); // const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance); diff --git a/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx b/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx index 5ae7932..441830e 100644 --- a/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx @@ -1,7 +1,8 @@ import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper/index.js'; import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; +import PromptEditor from '@/components/AIBasic/PromptEditor/index.js'; import { ReferenceForm } from '@/components/ReferenceForm/index.js'; -import type { NodeDataType } from '@/interfaces/flow.js'; +import type { BasicSchema, NodeDataType } from '@/interfaces/flow.js'; import { useFlowStore } from '@/stores/useFlowStore.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; @@ -16,9 +17,8 @@ type Props = { export const AgentNode = (props: Props) => { const { data } = props; // const { config } = data; - const { findUpstreamNodes } = useFlowStore(); + const { findUpstreamNodes, setNode } = useFlowStore(); const upstreamNodes = findUpstreamNodes(data.id.toString()); - console.log('🚀 ~ AgentNode ~ upstreamNodes:', upstreamNodes); return ( @@ -26,12 +26,65 @@ export const AgentNode = (props: Props) => { { - console.log('ReferenceForm', values); + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + input_param: [...values], + }, + }, + }, + })); }} /> - + + { + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + prompt: { + ...old.data.config.inputs.prompt, + value: values, + }, + }, + }, + }, + })); + }} + variableBlock={{ + show: true, + variables: data.config?.inputs?.input_param.map((input) => { + return { + name: input.name, + value: input.name, + }; + }), + }} + /> +
+ } + /> { <> {(data.config?.outputs || []).map((output) => ( ))} diff --git a/web-packages/magent-flow/src/components/Node/EndNode/index.tsx b/web-packages/magent-flow/src/components/Node/EndNode/index.tsx index a80f0f7..9c3681b 100644 --- a/web-packages/magent-flow/src/components/Node/EndNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/EndNode/index.tsx @@ -1,7 +1,7 @@ -import { Collapse } from 'antd'; - +import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper/index.js'; +import PromptEditor from '@/components/AIBasic/PromptEditor/index.js'; import { ReferenceForm } from '@/components/ReferenceForm/index.js'; -import type { NodeDataType } from '@/interfaces/flow.js'; +import type { BasicSchema, NodeDataType } from '@/interfaces/flow.js'; import { useFlowStore } from '@/stores/useFlowStore.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; @@ -15,21 +15,76 @@ type Props = { export const EndNode = (props: Props) => { const { data } = props; - const { findUpstreamNodes } = useFlowStore(); - const upstreamNode = findUpstreamNodes(data.id.toString()); + const { findUpstreamNodes, setNode } = useFlowStore(); + const upstreamNodes = findUpstreamNodes(data.id.toString()); return ( - - { - console.log('ReferenceForm', values); - }} - /> - + { + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + input_param: [...values], + }, + }, + }, + })); + }} + /> + + +
+ { + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + prompt: { + ...old.data.config.inputs.prompt, + value: values, + }, + }, + }, + }, + })); + }} + variableBlock={{ + show: true, + variables: data.config?.inputs?.input_param.map((input) => { + return { + name: input.name!, + value: input.name!, + }; + }), + }} + /> +
+ + } + >
); }; diff --git a/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx b/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx index 06ae870..7a99001 100644 --- a/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx @@ -1,8 +1,5 @@ -import { Form } from 'antd'; - -import { SelectInNode } from '@/components/AIBasic/SelectInNode/index.js'; -import { ReferenceSelect } from '@/components/ReferenceSelect/index.js'; -import type { NodeDataType } from '@/interfaces/flow.js'; +import { ConditionForm } from '@/components/ConditionForm/index.js'; +import type { NodeDataType, NodeType } from '@/interfaces/flow.js'; import { useFlowStore } from '@/stores/useFlowStore.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; @@ -16,11 +13,10 @@ type Props = { export const IfElseNode = (props: Props) => { const { data } = props; - const [form] = Form.useForm(); - const compare = Form.useWatch('compare', form); - const { findUpstreamNodes } = useFlowStore(); + + const { findUpstreamNodes, setNode } = useFlowStore(); const upstreamNode = findUpstreamNodes(data.id.toString()); - const options = upstreamNode.map((node) => { + const options = upstreamNode.map((node: NodeType) => { return { label: node.data.name, value: node.data.id, @@ -45,27 +41,26 @@ export const IfElseNode = (props: Props) => {
如果
- - - - - - - - {compare !== 'blank' && ( - - - - )} - + { + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + + inputs: { + ...old.data.config.inputs, + branches: [val], + }, + }, + }, + })); + }} + />
diff --git a/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx b/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx index 076b3c9..fe55f48 100644 --- a/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx @@ -20,7 +20,7 @@ type Props = { export const KnowledgeNode = (props: Props) => { const { data } = props; // const { config } = data; - const { findUpstreamNodes } = useFlowStore(); + const { findUpstreamNodes, setNode } = useFlowStore(); const { knowledges } = useKnowledgeStore(); const upstreamNode = findUpstreamNodes(data.id.toString()); @@ -31,9 +31,21 @@ export const KnowledgeNode = (props: Props) => { { - console.log('ReferenceForm', values); + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + input_param: [...values], + }, + }, + }, + })); }} /> { const { data } = props; - // console.log('🚀 ~ LLMNode ~ data:', data); - // const { config } = data; - const { findUpstreamNodes } = useFlowStore(); + const { findUpstreamNodes, setNode } = useFlowStore(); const upstreamNode = findUpstreamNodes(data.id.toString()); const { models, modelConfig } = useModelStore(); - const [value, setValue] = useState('hello'); return (
@@ -67,14 +64,25 @@ export const LLMNode = (props: Props) => { } /> {/* Part2 Ref Form */} - { - console.log('ReferenceForm', values); + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + input_param: [...values], + }, + }, + }, + })); }} /> {/* Part3 PromptEditor */} @@ -82,17 +90,37 @@ export const LLMNode = (props: Props) => { className="mt-3" label={'Prompt'} content={ -
+
setValue(val)} + onChange={(values) => { + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + prompt: { + ...old.data.config.inputs.prompt, + value: values, + }, + }, + }, + }, + })); + }} variableBlock={{ show: true, variables: data.config?.inputs?.input_param.map((input) => { return { - name: input.name!, - value: input.name!, + name: input.name, + value: input.name, }; }), }} @@ -103,13 +131,13 @@ export const LLMNode = (props: Props) => { {/* Part4 Outputer */} {(data.config?.outputs || []).map((output) => ( ))} diff --git a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx index 5800c27..fbd4bf8 100644 --- a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx +++ b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx @@ -14,7 +14,7 @@ type Props = { export const NodeWrapper = (props: { nodeProps: Props; - children: React.ReactElement; + children: React.ReactNode; leftHandler?: boolean; rightHandler?: boolean; rightHandlerConfig?: { @@ -30,9 +30,6 @@ export const NodeWrapper = (props: { rightHandlerConfig, } = props; const { name, description, icon } = nodeProps.data; - console.log('🚀 ~ nodeProps.selected:', nodeProps.selected); - // const runRes = {}; - // const validationStatus = true; return (
void; + value: BasicSchema[]; + onChange: (values: BasicSchema[]) => void; nodes: NodeType[]; dynamic?: boolean; } export const ReferenceForm = (props: RefrenceFormProps) => { - const { label, values, onChange, nodes, dynamic = false } = props; + const { label, value, onChange, nodes, dynamic = false } = props; const [form] = Form.useForm(); useEffect(() => { - form.setFieldValue('variables', values); + form.setFieldValue('variables', value); }, []); - console.log('🚀 ~ useEffect ~ values:', values); const options = nodes.map((node) => { return { @@ -46,7 +45,6 @@ export const ReferenceForm = (props: RefrenceFormProps) => { form={form} autoComplete="off" onValuesChange={(_, allFields) => { - console.log('🚀 ~ form.validateFields ~ allFields:', allFields); form.validateFields().then(() => { if (allFields.variables) { onChange(allFields.variables.filter((item: any) => item !== undefined)); diff --git a/web-packages/magent-flow/src/components/ReferenceSelect/index.tsx b/web-packages/magent-flow/src/components/ReferenceSelect/index.tsx index 28540cc..f4b94cb 100644 --- a/web-packages/magent-flow/src/components/ReferenceSelect/index.tsx +++ b/web-packages/magent-flow/src/components/ReferenceSelect/index.tsx @@ -1,29 +1,24 @@ import { Input } from 'antd'; -import React from 'react'; +import type { DefaultOptionType } from 'antd/es/cascader'; + +import type { SchemaValueType, ValueType } from '@/interfaces/flow.js'; import { CascaderInNode } from '../AIBasic/CascaderInNode/index.js'; import { SelectInNode } from '../AIBasic/SelectInNode/index.js'; export const ReferenceSelect = (props: { - value?: { - type: 'reference' | 'value'; - content?: string | [string, string]; - }; - onChange?: (value: { - type: 'reference' | 'value'; - content?: string | [string, string]; - }) => void; - refOptions: { label: string; content: string }[]; + value?: SchemaValueType; + onChange?: (value: SchemaValueType) => void; + refOptions: DefaultOptionType[]; }) => { const { value, onChange, refOptions } = props; - console.log('🚀 ~ value:', value); return (
+ onChange={(val: ValueType) => onChange?.({ type: val, }) @@ -48,9 +43,9 @@ export const ReferenceSelect = (props: { + onChange={(val: [string, string]) => onChange?.({ - type: value?.type, + type: value?.type || 'reference', content: val, }) } diff --git a/web-packages/magent-flow/src/components/VariableForm/index.tsx b/web-packages/magent-flow/src/components/VariableForm/index.tsx index eb70954..187cb62 100644 --- a/web-packages/magent-flow/src/components/VariableForm/index.tsx +++ b/web-packages/magent-flow/src/components/VariableForm/index.tsx @@ -89,6 +89,7 @@ export const VariableForm = (props: VariableFormProps) => { className="w-[200px]" > ((set, get) => { targetNode: string, ): Node[] => { const adjList: AdjacencyList = {}; + console.log('🚀 ~ nodes.forEach ~ nodes:', nodes); nodes.forEach((node) => { adjList[node.id] = []; }); @@ -80,11 +81,8 @@ export const useFlowStore = create((set, get) => { } }; - console.log('🚀 ~ useFlowStore ~ nodes:', nodes, edges, targetNode); - console.log('🚀 ~ adjList', adjList); - dfs(targetNode); - console.log('🚀 ~ result', result); + return get().nodes.filter((node) => Array.from(result).includes(node.id)); }; @@ -194,7 +192,6 @@ export const useFlowStore = create((set, get) => { oldEdges, ); - console.log('🚀 ~ get ~ newEdges:', newEdges); return newEdges; }); }, diff --git a/web/packages/magent-flow/src/components/ConditionForm/index.tsx b/web/packages/magent-flow/src/components/ConditionForm/index.tsx new file mode 100644 index 0000000..391dedd --- /dev/null +++ b/web/packages/magent-flow/src/components/ConditionForm/index.tsx @@ -0,0 +1,56 @@ +import { Form } from 'antd'; +import type { DefaultOptionType } from 'antd/es/cascader'; +import { memo, useEffect } from 'react'; + +import type { ConditionBranch } from '@/interfaces/flow.js'; + +import { SelectInNode } from '../AIBasic/SelectInNode//index.js'; +import { ReferenceSelect } from '../ReferenceSelect/index.js'; + +export const ConditionForm = (props: { + refOptions: DefaultOptionType[]; + value: ConditionBranch; + onChange: (val: ConditionBranch) => void; +}) => { + const { refOptions, value, onChange } = props; + const [form] = Form.useForm(); + const compare = Form.useWatch('compare', form); + + useEffect(() => { + form.setFieldsValue(value.conditions[0]); + }, []); + + return ( +
{ + form.validateFields().then(() => { + onChange({ + name: value.name, + conditions: [allFields], + }); + }); + }} + > + + + + + + + {compare !== 'blank' && ( + + + + )} +
+ ); +}; diff --git a/web/packages/magent-flow/src/components/Toolbar/index.tsx b/web/packages/magent-flow/src/components/Toolbar/index.tsx new file mode 100644 index 0000000..bd7b05a --- /dev/null +++ b/web/packages/magent-flow/src/components/Toolbar/index.tsx @@ -0,0 +1,23 @@ +import { Button } from 'antd'; + +import { useFlowStore } from '@/stores/useFlowStore.js'; +import { classNames } from '@/utils/basic.js'; + +export const Toolbar = (props: { classname?: string }) => { + const { classname } = props; + const { getFlow } = useFlowStore(); + return ( +
+ + +
+ ); +}; From 0f491b4fa66f548877fc74e0cc007b3d2c8ec77e Mon Sep 17 00:00:00 2001 From: "xujianfeng.xjf" Date: Wed, 28 Aug 2024 20:31:44 +0800 Subject: [PATCH 15/78] feat: update flow node ModelSelector & KnowledgeSelector --- web-apps/ui/package.json | 2 + .../components/model-selector/index.tsx | 188 +++++++------- .../agent-config/knowledge-modal/modal.tsx | 30 ++- web-apps/ui/src/views/agent-config/view.tsx | 8 +- .../src/views/agent-flow/agent-flow-view.tsx | 231 +++++++++++++++++- web-apps/ui/src/views/agent-flow/toolbar.tsx | 28 +++ web-packages/magent-flow/package.json | 1 + .../magent-flow/src/RefForm/index.tsx | 1 - .../magent-flow/src/components/Flow/index.tsx | 5 +- .../src/components/FlowWithPanel/index.tsx | 53 ++-- .../components/Node/KnowledgeNode/index.tsx | 39 +-- .../src/components/Node/LLMNode/index.tsx | 79 +++--- web-packages/magent-flow/src/index.ts | 5 + .../magent-flow/src/stores/useFlowStore.ts | 2 +- .../src/stores/useKnowledgeStore.ts | 18 +- .../magent-flow/src/stores/useModelStore.ts | 27 +- web-packages/magent-flow/tailwind.config.js | 7 +- .../src/components/Toolbar/index.tsx | 23 -- .../components/decimal-step/index.tsx | 33 +++ 19 files changed, 545 insertions(+), 235 deletions(-) create mode 100644 web-apps/ui/src/views/agent-flow/toolbar.tsx delete mode 100644 web/packages/magent-flow/src/components/Toolbar/index.tsx create mode 100644 web/ui/src/views/agent-config/components/decimal-step/index.tsx diff --git a/web-apps/ui/package.json b/web-apps/ui/package.json index 45fc42a..c4a005e 100644 --- a/web-apps/ui/package.json +++ b/web-apps/ui/package.json @@ -22,6 +22,7 @@ "deploy": "rimraf ../../packages/magent-ui/src/magent_ui/static && copyfiles -u 1 dist/* ../../packages/magent-ui/src/magent_ui/static/ && copyfiles -u 1 dist/**/* ../../packages/magent-ui/src/magent_ui/static/" }, "dependencies": { + "js-yaml": "^4.1.0", "@ant-design/icons": "^5.3.6", "@difizen/libro-jupyter": "^0.2.1", "@difizen/libro-lab": "^0.2.1", @@ -49,6 +50,7 @@ "umi": "^4.1.1" }, "devDependencies": { + "@types/js-yaml": "^4.0.9", "@babel/plugin-proposal-decorators": "^7.23.7", "@babel/plugin-transform-class-properties": "^7.23.3", "@babel/plugin-transform-flow-strip-types": "^7.23.3", diff --git a/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx b/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx index 5c0605c..d7b263f 100644 --- a/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx +++ b/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx @@ -12,6 +12,11 @@ import type { LLMMeta } from '@/modules/model/protocol.js'; import type { AgentConfigView } from '../../view.js'; +import './index.less'; +import { LLMManager } from '../../../../modules/model/llm-manager.js'; +import { DecimalStep } from '../decimal-step/index.js'; + +import { DefaultLogo, OpenAILogo, QwenLogo } from './logos.js'; import './index.less'; const clsPrefix = 'agent-config-model-selector'; @@ -38,104 +43,101 @@ const toKey = (model?: LLMMeta) => { return model.id + model.model_name[0]; }; -interface TemperatureSliderProps extends SliderSingleProps { - llm?: LLMProvider; -} -const TemperatureSlider: FC = ( - props: TemperatureSliderProps, -) => { - const llm = useObserve(props.llm); - const temperature = llm?.temperature; - return ( - { - if (llm) { - llm.temperature = v; - } - }} - value={temperature === undefined ? 1 : temperature} - /> - ); -}; +export const ModelSelector = forwardRef(function ModelSelectorComponent( + props: { + value?: LLMMeta; + onChange?: (value: LLMMeta) => void; + }, + ref, +) { + const { value, onChange } = props; -export const ModelSelector = forwardRef( - function ModelSelectorComponent(props, ref) { - const instance = useInject(ViewInstance); - const modelProviderManager = useInject(LLMProviderManager); + const modelManager = useInject(LLMManager); + // const defaultModel = modelManager.defaultModel; - const modelMeta = instance.agent?.llm; + const models = modelManager.models; - const models = modelProviderManager.models; + const metaModels = models + .map((item) => item.toSingleMetas()) + .filter((item) => !!item) + .flat() as ModelMeta[]; - const metaModels = models - .map((item) => item.toSingleMetas()) - .filter((item) => !!item) - .flat() as LLMMeta[]; + useEffect(() => { + modelManager.updateModels(); + }, [modelManager]); - useEffect(() => { - modelProviderManager.updateProviders(); - }, [modelProviderManager]); + const currentModel = metaModels.find((item) => value && toKey(item) === toKey(value)); - const currentModel = metaModels.find( - (item) => modelMeta && toKey(item) === toKey(modelMeta), - ); + const temperature = value?.temperature; - return ( -
- -
- - - - - - -
-
- } + return ( +
+ triggerNode.parentElement} + arrow={false} + placement="bottomLeft" + title="模型设置" + trigger="click" + content={ +
+
+ + + + + { + if (value) { + onChange?.({ + ...value, + temperature: v, + }); + } + }} + value={temperature === undefined ? 1 : Number(temperature)} + /> + +
+
+ } + > + -
-
- ); - }, -); + {currentModel ? : null} + + +
+ ); +}); diff --git a/web-apps/ui/src/views/agent-config/knowledge-modal/modal.tsx b/web-apps/ui/src/views/agent-config/knowledge-modal/modal.tsx index f741115..e75c7ac 100644 --- a/web-apps/ui/src/views/agent-config/knowledge-modal/modal.tsx +++ b/web-apps/ui/src/views/agent-config/knowledge-modal/modal.tsx @@ -1,22 +1,26 @@ import type { ModalItem, ModalItemProps } from '@difizen/mana-app'; -import { useInject, useMount } from '@difizen/mana-app'; +import { useInject, useMount, useObserve } from '@difizen/mana-app'; import type { TableColumnsType } from 'antd'; import { Modal, Table } from 'antd'; import type { TableRowSelection } from 'antd/es/table/interface.js'; import { useMemo } from 'react'; -import type { AgentModel } from '@/modules/agent/protocol.js'; import { KnowledgeIcon } from '@/modules/knowledge/knowledge-icon.js'; import { KnowledgeSpace } from '@/modules/knowledge/knowledge-space.js'; import type { KnowledgeModelOption } from '@/modules/knowledge/protocol.js'; + import { KnowledgeModalId } from '../protocol.js'; export const KnowledgeModalComponent = ( - props: ModalItemProps<{ agent: AgentModel }>, + props: ModalItemProps<{ + dataProvider: { knowledge: KnowledgeModelOption[] }; + onChange: (knowledge: KnowledgeModelOption[]) => void; + }>, ) => { const knowledgeSpace = useInject(KnowledgeSpace); const { visible, close } = props; - const { agent } = props.data || {}; + const { onChange } = props.data || {}; + const dataProvider = useObserve(props.data?.dataProvider); const columns = useMemo(() => { const c: TableColumnsType = [ @@ -53,21 +57,23 @@ export const KnowledgeModalComponent = ( knowledgeSpace.update(); }); - if (!agent) { - return null; - } - const onSelectChange = (newSelectedRowKeys: React.Key[]) => { - agent.knowledge = knowledgeSpace.list - .filter((item) => newSelectedRowKeys.includes(item.id)) - .map((item) => item.toMeta()); + onChange?.( + knowledgeSpace.list + .filter((item) => newSelectedRowKeys.includes(item.id)) + .map((item) => item.toMeta()), + ); }; const rowSelection: TableRowSelection = { - selectedRowKeys: (agent.knowledge || []).map((item) => item.id), + selectedRowKeys: (dataProvider?.knowledge || []).map((item) => item.id), onChange: onSelectChange, }; + if (!dataProvider?.knowledge) { + return null; + } + return ( ( }), onAdd: () => { if (instance.agent) { - modalService.openModal(KnowledgeModal, { agent: instance.agent }); + modalService.openModal(KnowledgeModal, { + dataProvider: instance.agent, + onChange: (knowledges: KnowledgeModelOption[]) => { + instance.agent.knowledge = [...knowledges]; + }, + }); } }, onDelete: (item) => { diff --git a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx index ea735c3..3a5de0f 100644 --- a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx +++ b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx @@ -1,19 +1,238 @@ -import { FlowWithPanel } from '@difizen/magent-flow'; +import { DeleteOutlined } from '@ant-design/icons'; +import type { BasicSchema } from '@difizen/magent-flow'; +import { + FlowWithPanel, + useFlowStore, + useKnowledgeStore, + useModelStore, +} from '@difizen/magent-flow'; import { BaseView, inject, prop, view, ViewOption, transient } from '@difizen/mana-app'; -import { forwardRef } from 'react'; - -import { AgentManager } from '@/modules/agent/agent-manager.js'; -import type { AgentModel } from '@/modules/agent/protocol.js'; +import { Button } from 'antd'; +import { forwardRef, useEffect, useState } from 'react'; +import { AgentManager } from '../../modules/agent/index.js'; +import type { AgentModel, LLMMeta } from '../../modules/agent/index.js'; import './index.less'; +import type { KnowledgeModelOption } from '../../modules/knowledge/protocol.js'; +import { ModelSelector } from '../agent-config/components/model-selector/index.js'; +import { + KnowledgeModal, + KnowledgeModalComponent, +} from '../agent-config/knowledge-modal/modal.js'; + +import { Toolbar } from './toolbar.js'; const viewId = 'magent-agent-flow'; const AgentFlowComponent = forwardRef( function AgentConfigViewComponent(props, ref) { + const { setModelSelector } = useModelStore(); + const { setKnowledgeSelector } = useKnowledgeStore(); + const { setNode } = useFlowStore(); + + useEffect(() => { + // 注册 flow 中模型选择 + const Ele = ({ + nodeId, + llmParam, + }: { + nodeId: string; + llmParam: BasicSchema[]; + }) => { + const onChange = (val: LLMMeta) => { + setNode(nodeId, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + llm_param: [ + llmParam.find((p) => p.name === 'prompt'), + { + name: 'id', + type: 'string', + value: { + type: 'value', + content: val.id, + }, + }, + { + name: 'temperature', + type: 'string', + value: { + type: 'value', + content: val.temperature, + }, + }, + { + name: 'model_name', + type: 'string', + value: { + type: 'value', + content: val.model_name, + }, + }, + ], + }, + }, + }, + })); + }; + const value: LLMMeta = { + id: llmParam.find((p) => p.name === 'id')?.value?.content as string, + temperature: Number( + llmParam.find((p) => p.name === 'temperature')?.value?.content as string, + ), + nickname: '', + model_name: [ + llmParam.find((p) => p.name === 'model_name')?.value?.content as string, + ], + }; + return ( + <> + + + ); + }; + setModelSelector(Ele as any); + const Ele2 = ({ + nodeId, + knowledgeParam, + }: { + nodeId: string; + knowledgeParam: BasicSchema[]; + }) => { + const [knowledgeModal, setKnowledgeModal] = useState(false); + + const onChange = (val: any) => { + setNode(nodeId, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + knowledge_param: [ + { + name: 'top_k', + type: 'string', + value: { + type: 'value', + content: val.top_k, + }, + }, + { + name: 'id', + type: 'string', + value: { + type: 'value', + content: val.id, + }, + }, + ], + }, + }, + }, + })); + }; + + const value: any = { + knowledge: ( + (knowledgeParam.find((p) => p.name === 'id')?.value?.content || + []) as string[] + ).map((k) => ({ id: k })), + top_k: knowledgeParam.find((p) => p.name === 'top_k')?.value + ?.content as string, + }; + + return ( + <> + setKnowledgeModal(false)} + data={{ + dataProvider: { knowledge: [...value.knowledge] }, + onChange: (knowledges: KnowledgeModelOption[]) => { + onChange({ + id: [...knowledges.map((k) => k.id)], + top_k: value.top_k, + }); + }, + }} + modalItem={KnowledgeModal} + /> +
+
+ {value.knowledge.map((k) => ( +
+
{k.id}
+ +
+ ))} +
+ +
+ + ); + }; + setKnowledgeSelector(Ele2 as any); + }, []); + return (
- + + } + />
); }, diff --git a/web-apps/ui/src/views/agent-flow/toolbar.tsx b/web-apps/ui/src/views/agent-flow/toolbar.tsx new file mode 100644 index 0000000..0021bf5 --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/toolbar.tsx @@ -0,0 +1,28 @@ +import { useFlowStore } from '@difizen/magent-flow'; +import { Button } from 'antd'; +import classNames from 'classnames'; +import yaml from 'js-yaml'; +import React from 'react'; + +export const Toolbar = (props: { classname?: string; style?: React.CSSProperties }) => { + const { classname, style } = props; + const { getFlow } = useFlowStore(); + return ( +
+ + +
+ ); +}; diff --git a/web-packages/magent-flow/package.json b/web-packages/magent-flow/package.json index 3a1285b..1ce039c 100644 --- a/web-packages/magent-flow/package.json +++ b/web-packages/magent-flow/package.json @@ -71,6 +71,7 @@ }, "devDependencies": { "@types/classnames": "^2.3.1", + "@types/js-yaml": "^4.0.9", "@types/lodash": "^4.17.7", "@types/react": "^18.2.25", "@types/uuid": "^10.0.0", diff --git a/web-packages/magent-flow/src/RefForm/index.tsx b/web-packages/magent-flow/src/RefForm/index.tsx index b7b66a1..a9bbaf6 100644 --- a/web-packages/magent-flow/src/RefForm/index.tsx +++ b/web-packages/magent-flow/src/RefForm/index.tsx @@ -160,7 +160,6 @@ const Parameter = (props: { className="noflow nowheel nopan nodelete nodrag" options={options} onChange={(v) => { - console.log('🚀 ~ v:', v); setValue((s) => { return { ...s, diff --git a/web-packages/magent-flow/src/components/Flow/index.tsx b/web-packages/magent-flow/src/components/Flow/index.tsx index 55cb297..6aa46fb 100644 --- a/web-packages/magent-flow/src/components/Flow/index.tsx +++ b/web-packages/magent-flow/src/components/Flow/index.tsx @@ -32,10 +32,11 @@ interface FlowProps { miniMap?: boolean; classNames?: string; nodeTypes: any; + toolbar: React.ReactNode; } function Flow(props: FlowProps) { - const { miniMap = true, classNames, nodeTypes } = props; + const { miniMap = true, classNames, nodeTypes, toolbar } = props; const position = useRef({ x: 0, y: 0 }); const [lastSelection, setLastSelection] = useState( null, @@ -161,7 +162,7 @@ function Flow(props: FlowProps) { > {miniMap && } - + {toolbar}
); diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx index afd719d..e68272d 100644 --- a/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx +++ b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx @@ -67,34 +67,39 @@ const yamlContent = ` llm_param: - type: string name: id - value: qwen_llm + value: + type: value + content: qwen_llm - type: string name: model_name - value: qwen-max + value: + content: qwen-max + type: value - type: string name: temperature - value: '0.7' + value: + content: '0.7' + type: value - type: string - prompt: - type: string - value: - type: value - content: | - 你是一位精通信息分析的ai助手。你的目标是使用中文结合查询的背景信息及你所拥有的知识回答用户提出的问题。 - 你需要遵守的规则是: - 1. 必须使用中文结合查询的背景信息结合你所拥有的知识回答用户提出的问题。 - 2. 结构化答案生成,必要时通过空行提升阅读体验。 - 3. 不采用背景信息中的错误信息。 - 4. 要考虑答案和问题的相关性,不做对问题没有帮助的回答。 - 5. 详尽回答问题,重点突出,不过多花哨词藻。 - 6. 不说模糊的推测。 - 7. 尽量多的使用数值类信息。 + name: prompt + value: + type: value + content: | + 你是一位精通信息分析的ai助手。你的目标是使用中文结合查询的背景信息及你所拥有的知识回答用户提出的问题。 + 你需要遵守的规则是: + 1. 必须使用中文结合查询的背景信息结合你所拥有的知识回答用户提出的问题。 + 2. 结构化答案生成,必要时通过空行提升阅读体验。 + 3. 不采用背景信息中的错误信息。 + 4. 要考虑答案和问题的相关性,不做对问题没有帮助的回答。 + 5. 详尽回答问题,重点突出,不过多花哨词藻。 + 6. 不说模糊的推测。 + 7. 尽量多的使用数值类信息。 - 背景信息是: - {{background}} + 背景信息是: + {{background}} - 开始! - 需要回答的问题是: {{input}} + 开始! + 需要回答的问题是: {{input}} outputs: - type: string name: output @@ -107,7 +112,6 @@ const yamlContent = ` knowledge_param: - type: string name: id - value: demo_knowledge - type: string name: top_k value: @@ -200,7 +204,8 @@ const nodeTypes = { [NodeTypeEnum.Agent]: AgentNode, }; -export const FlowWithPanel = () => { +export const FlowWithPanel = (props: { toolbar?: React.ReactNode }) => { + const { toolbar } = props; const yaml_data = yaml.load(yamlContent); (yaml_data as Record[]).forEach((item) => { NodeSchemaParser(item); @@ -226,7 +231,7 @@ export const FlowWithPanel = () => {
- +
); diff --git a/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx b/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx index fe55f48..b7c8376 100644 --- a/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx @@ -4,7 +4,7 @@ import { Button, Modal } from 'antd'; import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper/index.js'; import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; import { ReferenceForm } from '@/components/ReferenceForm/index.js'; -import type { NodeDataType } from '@/interfaces/flow.js'; +import type { BasicSchema, NodeDataType } from '@/interfaces/flow.js'; import { useFlowStore } from '@/stores/useFlowStore.js'; import { useKnowledgeStore } from '@/stores/useKnowledgeStore.js'; @@ -22,9 +22,11 @@ export const KnowledgeNode = (props: Props) => { // const { config } = data; const { findUpstreamNodes, setNode } = useFlowStore(); - const { knowledges } = useKnowledgeStore(); + const { KnowledgeSelector } = useKnowledgeStore(); const upstreamNode = findUpstreamNodes(data.id.toString()); + const knowledge_param = data.config?.inputs?.knowledge_param as BasicSchema[]; + return (
@@ -50,31 +52,16 @@ export const KnowledgeNode = (props: Props) => { /> -
知识库配置
- -
+ label={'知识库配置'} + content={ + <> + {KnowledgeSelector !== null ? ( + + ) : ( + <>知识库配置 + )} + } - content={<>List} /> { const { data } = props; const { findUpstreamNodes, setNode } = useFlowStore(); + const { ModelSelector, modelOptions, modelConfig } = useModelStore(); + const upstreamNode = findUpstreamNodes(data.id.toString()); - const { models, modelConfig } = useModelStore(); + const llm_param = data.config?.inputs?.llm_param as BasicSchema[]; return ( @@ -36,31 +38,35 @@ export const LLMNode = (props: Props) => { className="mb-3" label={'模型配置'} content={ -
- ({ - label: model.name, - value: model.id, - }))} - className="w-full mr-2" - /> - - {Object.entries(modelConfig).map(([key, value]) => ( - <> - {key} - - ))} -
- } - > - {Object.entries(modelConfig).length > 0 && ( - - )} - -
+ ModelSelector !== null ? ( + + ) : ( +
+ ({ + label: model.name, + value: model.id, + }))} + className="w-full mr-2" + /> + + {Object.entries(modelConfig).map(([key, value]) => ( + <> + {key} + + ))} +
+ } + > + {Object.entries(modelConfig).length > 0 && ( + + )} + +
+ ) } /> {/* Part2 Ref Form */} @@ -68,7 +74,7 @@ export const LLMNode = (props: Props) => { label="输入变量" dynamic nodes={[...(upstreamNode as any)]} - value={[...(data.config?.inputs?.input_param || [])]} + value={[...(data.config.inputs?.input_param || [])]} onChange={(values) => { setNode(data.id, (old) => ({ ...old, @@ -93,7 +99,7 @@ export const LLMNode = (props: Props) => {
item.name === 'prompt')?.value ?.content as string) || '' } placeholder="请输入 Prompt" @@ -106,10 +112,17 @@ export const LLMNode = (props: Props) => { ...(old.data.config as Record), inputs: { ...old.data.config.inputs, - prompt: { - ...old.data.config.inputs.prompt, - value: values, - }, + llm_param: [ + ...llm_param, + { + name: 'prompt', + type: 'string', + value: { + type: 'value', + content: values, + }, + }, + ], }, }, }, diff --git a/web-packages/magent-flow/src/index.ts b/web-packages/magent-flow/src/index.ts index e6d7f38..bd969b6 100644 --- a/web-packages/magent-flow/src/index.ts +++ b/web-packages/magent-flow/src/index.ts @@ -3,6 +3,11 @@ export { FlowWithPanel } from './components/FlowWithPanel/index.js'; export { FormSchema } from './FormSchema/index.js'; export { RefForm } from './RefForm/index.js'; export { SchemaConfigForm } from './SchemaConfigForm/index.js'; +export { useFlowStore } from './stores/useFlowStore.js'; +export { useModelStore } from './stores/useModelStore.js'; +export { useKnowledgeStore } from './stores/useKnowledgeStore.js'; export { StartNode } from './spec/node.js'; export * from './utils/index.js'; import './tailwind.out.css'; + +export * from './interfaces/flow.js'; diff --git a/web-packages/magent-flow/src/stores/useFlowStore.ts b/web-packages/magent-flow/src/stores/useFlowStore.ts index d9c0158..037c32d 100644 --- a/web-packages/magent-flow/src/stores/useFlowStore.ts +++ b/web-packages/magent-flow/src/stores/useFlowStore.ts @@ -56,7 +56,7 @@ export const useFlowStore = create((set, get) => { targetNode: string, ): Node[] => { const adjList: AdjacencyList = {}; - console.log('🚀 ~ nodes.forEach ~ nodes:', nodes); + nodes.forEach((node) => { adjList[node.id] = []; }); diff --git a/web-packages/magent-flow/src/stores/useKnowledgeStore.ts b/web-packages/magent-flow/src/stores/useKnowledgeStore.ts index 908657a..7c9c063 100644 --- a/web-packages/magent-flow/src/stores/useKnowledgeStore.ts +++ b/web-packages/magent-flow/src/stores/useKnowledgeStore.ts @@ -1,19 +1,25 @@ import { create } from 'zustand'; +import type { BasicSchema } from '@/interfaces/flow.js'; + export interface Knowledge { name: string; id: string; description?: string; } +export type KnowledgeSelectorNode = + | ((props: { nodeId: string; knowledgeParam: BasicSchema[] }) => React.ReactNode) + | null; + export interface KnowledgeStoreType { - knowledges: Knowledge[]; - setKnowledges: (knowledges: Knowledge[]) => void; + KnowledgeSelector: KnowledgeSelectorNode | null; + setKnowledgeSelector: (KnowledgeSelector: KnowledgeSelectorNode) => void; } -export const useKnowledgeStore = create((set, get) => ({ - knowledges: [], - setKnowledges: (knowledges: Knowledge[]) => { - set({ knowledges }); +export const useKnowledgeStore = create((set) => ({ + KnowledgeSelector: null, + setKnowledgeSelector: (KnowledgeSelector) => { + set({ KnowledgeSelector }); }, })); diff --git a/web-packages/magent-flow/src/stores/useModelStore.ts b/web-packages/magent-flow/src/stores/useModelStore.ts index fa9a09e..6326ef6 100644 --- a/web-packages/magent-flow/src/stores/useModelStore.ts +++ b/web-packages/magent-flow/src/stores/useModelStore.ts @@ -1,5 +1,9 @@ +import type React from 'react'; import { create } from 'zustand'; +import type { BasicSchema } from '@/interfaces/flow.js'; + +// 注册 模型选择和配置组件 提供onChange事件 export interface Model { id: string; name: string; @@ -14,17 +18,28 @@ export interface ModelConfig { [key: string]: number | undefined; } +export type ModelSelectorNode = + | ((props: { nodeId: string; llmParam: BasicSchema[] }) => React.ReactNode) + | null; + export interface ModelStoreType { - models: Model[]; - setModels: (models: Model[]) => void; + ModelSelector: ModelSelectorNode; + setModelSelector: (ModelSelector: ModelSelectorNode) => void; + modelOptions: Model[]; + setModelOptions: (models: Model[]) => void; modelConfig: ModelConfig; setModelConfig: (config: ModelConfig) => void; } -export const useModelStore = create((set, get) => ({ - models: [], - setModels: (models: Model[]) => { - set({ models }); +export const useModelStore = create((set) => ({ + ModelSelector: null, + setModelSelector: (ModelSelector) => { + set({ ModelSelector }); + }, + + modelOptions: [], + setModelOptions: (modelOptions: Model[]) => { + set({ modelOptions }); }, modelConfig: {}, setModelConfig: (modelConfig: ModelConfig) => { diff --git a/web-packages/magent-flow/tailwind.config.js b/web-packages/magent-flow/tailwind.config.js index 9cfd53f..87a3fba 100644 --- a/web-packages/magent-flow/tailwind.config.js +++ b/web-packages/magent-flow/tailwind.config.js @@ -1,7 +1,12 @@ -module.exports = { +/** @type {import('tailwindcss').Config} */ +export default { content: [ './src/pages/**/*.tsx', './src/components/**/*.tsx', './src/layouts/**/*.tsx', ], + theme: { + extend: {}, + }, + plugins: [], }; diff --git a/web/packages/magent-flow/src/components/Toolbar/index.tsx b/web/packages/magent-flow/src/components/Toolbar/index.tsx deleted file mode 100644 index bd7b05a..0000000 --- a/web/packages/magent-flow/src/components/Toolbar/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Button } from 'antd'; - -import { useFlowStore } from '@/stores/useFlowStore.js'; -import { classNames } from '@/utils/basic.js'; - -export const Toolbar = (props: { classname?: string }) => { - const { classname } = props; - const { getFlow } = useFlowStore(); - return ( -
- - -
- ); -}; diff --git a/web/ui/src/views/agent-config/components/decimal-step/index.tsx b/web/ui/src/views/agent-config/components/decimal-step/index.tsx new file mode 100644 index 0000000..17da4a9 --- /dev/null +++ b/web/ui/src/views/agent-config/components/decimal-step/index.tsx @@ -0,0 +1,33 @@ +import { InputNumber, Slider } from 'antd'; + +export const DecimalStep = (props: { + min: number; + max: number; + step: number; + value: number; + onChange: (value: number) => void; +}) => { + const { min, max, step, value, onChange } = props; + + return ( +
+ + + +
+ ); +}; From d1a3b7accb66548589ad7176ecc4229b332f0a57 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Thu, 29 Aug 2024 00:51:34 +0800 Subject: [PATCH 16/78] fix(ui): migrate util api --- packages/magent-ui/src/magent_ui/routers/common/router.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/magent-ui/src/magent_ui/routers/common/router.py b/packages/magent-ui/src/magent_ui/routers/common/router.py index 81d912f..88c3a12 100644 --- a/packages/magent-ui/src/magent_ui/routers/common/router.py +++ b/packages/magent-ui/src/magent_ui/routers/common/router.py @@ -3,7 +3,7 @@ import json from typing import AsyncIterable, List from fastapi import APIRouter -import agentuniverse_product.service.util.product_util as util +from agentuniverse_product.service.util.agent_util import is_component_id_unique router = APIRouter() common_router = router @@ -11,6 +11,6 @@ @router.get("/common/is_id_unique", response_model=bool) async def is_id_unique(id:str, type:str): - result = util.is_id_unique(id,type) + result = is_component_id_unique(id,type) return result From b418dd7bfe540032220cdaa59ea8fabc5b4911f7 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Thu, 29 Aug 2024 00:57:49 +0800 Subject: [PATCH 17/78] fix(ui): remaining issues with code merging --- .../components/decimal-step/index.tsx | 0 .../components/model-selector/index.tsx | 29 +++++++++---------- .../src/views/agent-flow/agent-flow-view.tsx | 18 +++++++----- web-apps/ui/src/views/agents/modal/create.tsx | 3 ++ .../src/components/ConditionForm/index.tsx | 20 ++++++++----- 5 files changed, 38 insertions(+), 32 deletions(-) rename {web => web-apps}/ui/src/views/agent-config/components/decimal-step/index.tsx (100%) rename {web/packages => web-packages}/magent-flow/src/components/ConditionForm/index.tsx (81%) diff --git a/web/ui/src/views/agent-config/components/decimal-step/index.tsx b/web-apps/ui/src/views/agent-config/components/decimal-step/index.tsx similarity index 100% rename from web/ui/src/views/agent-config/components/decimal-step/index.tsx rename to web-apps/ui/src/views/agent-config/components/decimal-step/index.tsx diff --git a/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx b/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx index d7b263f..042ba2f 100644 --- a/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx +++ b/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx @@ -1,22 +1,13 @@ import { CaretDownOutlined } from '@ant-design/icons'; -import { ViewInstance, useInject, useObserve } from '@difizen/mana-app'; -import type { SliderSingleProps } from 'antd'; -import { Button, Form, Select, Popover, Avatar, Slider } from 'antd'; -import type { FC } from 'react'; +import { useInject } from '@difizen/mana-app'; +import { Button, Form, Select, Popover, Avatar } from 'antd'; import { forwardRef, useEffect } from 'react'; -import type { LLMProvider } from '@/modules/model/llm-model.js'; import { LLMProviderManager } from '@/modules/model/llm-provider-manager.js'; import { LLMIcon } from '@/modules/model/model-icon/index.js'; import type { LLMMeta } from '@/modules/model/protocol.js'; -import type { AgentConfigView } from '../../view.js'; - -import './index.less'; -import { LLMManager } from '../../../../modules/model/llm-manager.js'; import { DecimalStep } from '../decimal-step/index.js'; - -import { DefaultLogo, OpenAILogo, QwenLogo } from './logos.js'; import './index.less'; const clsPrefix = 'agent-config-model-selector'; @@ -43,7 +34,13 @@ const toKey = (model?: LLMMeta) => { return model.id + model.model_name[0]; }; -export const ModelSelector = forwardRef(function ModelSelectorComponent( +export const ModelSelector = forwardRef< + HTMLDivElement, + { + value?: LLMMeta; + onChange?: (value: LLMMeta) => void; + } +>(function ModelSelectorComponent( props: { value?: LLMMeta; onChange?: (value: LLMMeta) => void; @@ -52,7 +49,7 @@ export const ModelSelector = forwardRef(function ModelSelectorCo ) { const { value, onChange } = props; - const modelManager = useInject(LLMManager); + const modelManager = useInject(LLMProviderManager); // const defaultModel = modelManager.defaultModel; const models = modelManager.models; @@ -60,10 +57,10 @@ export const ModelSelector = forwardRef(function ModelSelectorCo const metaModels = models .map((item) => item.toSingleMetas()) .filter((item) => !!item) - .flat() as ModelMeta[]; + .flat() as LLMMeta[]; useEffect(() => { - modelManager.updateModels(); + modelManager.updateProviders(); }, [modelManager]); const currentModel = metaModels.find((item) => value && toKey(item) === toKey(value)); @@ -74,7 +71,7 @@ export const ModelSelector = forwardRef(function ModelSelectorCo
triggerNode.parentElement} + getPopupContainer={(triggerNode) => triggerNode.parentElement!} arrow={false} placement="bottomLeft" title="模型设置" diff --git a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx index 3a5de0f..28d936d 100644 --- a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx +++ b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx @@ -10,10 +10,12 @@ import { BaseView, inject, prop, view, ViewOption, transient } from '@difizen/ma import { Button } from 'antd'; import { forwardRef, useEffect, useState } from 'react'; -import { AgentManager } from '../../modules/agent/index.js'; -import type { AgentModel, LLMMeta } from '../../modules/agent/index.js'; +import { AgentManager } from '@/modules/agent/agent-manager.js'; +import type { AgentModel } from '@/modules/agent/protocol.js'; import './index.less'; -import type { KnowledgeModelOption } from '../../modules/knowledge/protocol.js'; +import type { KnowledgeModelOption } from '@/modules/knowledge/protocol.js'; +import type { LLMMeta } from '@/modules/model/protocol.js'; + import { ModelSelector } from '../agent-config/components/model-selector/index.js'; import { KnowledgeModal, @@ -45,9 +47,9 @@ const AgentFlowComponent = forwardRef( data: { ...old.data, config: { - ...(old.data.config as Record), + ...(old.data['config'] as Record), inputs: { - ...old.data.config.inputs, + ...old.data['config'].inputs, llm_param: [ llmParam.find((p) => p.name === 'prompt'), { @@ -112,9 +114,9 @@ const AgentFlowComponent = forwardRef( data: { ...old.data, config: { - ...(old.data.config as Record), + ...(old.data['config'] as Record), inputs: { - ...old.data.config.inputs, + ...old.data['config'].inputs, knowledge_param: [ { name: 'top_k', @@ -217,7 +219,7 @@ const AgentFlowComponent = forwardRef( ); }; setKnowledgeSelector(Ele2 as any); - }, []); + }, [setKnowledgeSelector, setModelSelector, setNode]); return (
diff --git a/web-apps/ui/src/views/agents/modal/create.tsx b/web-apps/ui/src/views/agents/modal/create.tsx index 03abb82..6f546ef 100644 --- a/web-apps/ui/src/views/agents/modal/create.tsx +++ b/web-apps/ui/src/views/agents/modal/create.tsx @@ -13,6 +13,7 @@ import { AgentTypeSelector } from '@/components/agent-type-selector/index.js'; import { AvatarUpload } from '@/components/avatar-upload/index.js'; import { AgentIcon } from '@/modules/agent/agent-icon.js'; import { AgentManager } from '@/modules/agent/agent-manager.js'; +import { AgentMarket } from '@/modules/agent/agent-market.js'; import { RequestHelper } from '@/modules/axios-client/request.js'; import { LLMManager } from '@/modules/model/llm-manager.js'; import { ModelSelector } from '@/modules/model/model-selector/index.js'; @@ -68,6 +69,7 @@ export const AgentModalComponent = (props: ModalItemProps) => { const agentManager = useInject(AgentManager); const llmManager = useInject(LLMManager); const req = useInject(RequestHelper); + const market = useInject(AgentMarket); const { visible, close } = props; const [form] = Form.useForm<{ id: string; @@ -125,6 +127,7 @@ export const AgentModalComponent = (props: ModalItemProps) => { const res = await agentManager.create(meta); if (res.status === 200) { close(); + market.update(); history.push( `/agent/${meta.id}/${meta.planner.id === 'workflow_planner' ? 'flow' : 'dev'}`, ); diff --git a/web/packages/magent-flow/src/components/ConditionForm/index.tsx b/web-packages/magent-flow/src/components/ConditionForm/index.tsx similarity index 81% rename from web/packages/magent-flow/src/components/ConditionForm/index.tsx rename to web-packages/magent-flow/src/components/ConditionForm/index.tsx index 391dedd..3c35ddf 100644 --- a/web/packages/magent-flow/src/components/ConditionForm/index.tsx +++ b/web-packages/magent-flow/src/components/ConditionForm/index.tsx @@ -1,6 +1,6 @@ import { Form } from 'antd'; import type { DefaultOptionType } from 'antd/es/cascader'; -import { memo, useEffect } from 'react'; +import { useEffect } from 'react'; import type { ConditionBranch } from '@/interfaces/flow.js'; @@ -18,19 +18,23 @@ export const ConditionForm = (props: { useEffect(() => { form.setFieldsValue(value.conditions[0]); - }, []); + }, [form, value.conditions]); return (
{ - form.validateFields().then(() => { - onChange({ - name: value.name, - conditions: [allFields], - }); - }); + form + .validateFields() + .then(() => { + onChange({ + name: value.name, + conditions: [allFields], + }); + return; + }) + .catch(console.error); }} > From 052d01b554fb7fc89221a75088b038d156017a2f Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Thu, 29 Aug 2024 03:20:46 +0800 Subject: [PATCH 18/78] feat(ui): project settings are more convenient for development and optimized flow styles --- web-apps/ui/config/config.ts | 5 + .../src/views/agent-flow/agent-flow-view.tsx | 6 +- .../ui/src/views/agent-flow/flow-dev-view.tsx | 10 +- web-apps/ui/src/views/agent-flow/index.less | 14 +-- web-apps/ui/src/views/agent-flow/toolbar.tsx | 19 +++- web-apps/ui/src/views/agents/view.tsx | 18 ++-- web-apps/ui/src/views/chat/view.tsx | 94 ++++++++----------- web-packages/magent-flow/.eslintignore | 3 + .../magent-flow/src/FormSchema/index.ts | 3 +- .../magent-flow/src/RefForm/index.tsx | 5 +- .../src/SchemaConfigForm/index.tsx | 6 +- .../AIBasic/CascaderInNode/index.tsx | 2 +- .../OutputVariable/index.tsx | 2 +- .../plugins/component-picker-block/index.tsx | 2 +- .../PromptEditor/plugins/update-block.tsx | 2 +- .../components/AIBasic/SelectInNode/index.tsx | 2 +- .../src/components/ConditionForm/index.tsx | 9 +- .../magent-flow/src/components/Flow/index.tsx | 17 ++-- .../magent-flow/src/components/Flow/keys.ts | 2 +- .../components/FlowWithPanel/icons/agent.svg | 1 + .../components/FlowWithPanel/icons/end.svg | 1 + .../components/FlowWithPanel/icons/ifelse.svg | 1 + .../FlowWithPanel/icons/knowledge.svg | 1 + .../components/FlowWithPanel/icons/llm.svg | 1 + .../components/FlowWithPanel/icons/start.svg | 1 + .../components/FlowWithPanel/icons/tool.svg | 1 + .../src/components/FlowWithPanel/index.tsx | 34 +++++-- .../src/components/Node/AgentNode/index.tsx | 12 +-- .../src/components/Node/CommonNode/index.tsx | 2 +- .../src/components/Node/EndNode/index.tsx | 10 +- .../src/components/Node/IfElseNode/index.tsx | 8 +- .../components/Node/KnowledgeNode/index.tsx | 12 +-- .../src/components/Node/LLMNode/index.tsx | 16 ++-- .../Node/NodeWrapper/Status/index.tsx | 2 +- .../src/components/Node/NodeWrapper/index.tsx | 7 +- .../src/components/Node/StartNode/index.tsx | 28 +++--- .../src/components/NodePanel/index.tsx | 5 +- .../src/components/ReferenceForm/index.tsx | 2 +- .../src/components/ReferenceSelect/index.tsx | 2 +- .../src/components/VariableForm/index.tsx | 3 +- .../magent-flow/src/interfaces/flow.ts | 10 +- .../magent-flow/src/spec/node.test.ts | 3 - web-packages/magent-flow/src/spec/node.ts | 4 +- .../magent-flow/src/stores/useFlowStore.ts | 4 +- .../src/stores/useKnowledgeStore.ts | 2 +- .../magent-flow/src/stores/useModelStore.ts | 2 +- .../src/stores/useShortcutsStore.ts | 2 +- .../src/stores/useUndoRedoStore.ts | 1 - web-packages/magent-flow/tsconfig.json | 2 +- 49 files changed, 211 insertions(+), 190 deletions(-) create mode 100644 web-packages/magent-flow/.eslintignore create mode 100644 web-packages/magent-flow/src/components/FlowWithPanel/icons/agent.svg create mode 100644 web-packages/magent-flow/src/components/FlowWithPanel/icons/end.svg create mode 100644 web-packages/magent-flow/src/components/FlowWithPanel/icons/ifelse.svg create mode 100644 web-packages/magent-flow/src/components/FlowWithPanel/icons/knowledge.svg create mode 100644 web-packages/magent-flow/src/components/FlowWithPanel/icons/llm.svg create mode 100644 web-packages/magent-flow/src/components/FlowWithPanel/icons/start.svg create mode 100644 web-packages/magent-flow/src/components/FlowWithPanel/icons/tool.svg diff --git a/web-apps/ui/config/config.ts b/web-apps/ui/config/config.ts index dcc0c35..87a4364 100644 --- a/web-apps/ui/config/config.ts +++ b/web-apps/ui/config/config.ts @@ -60,6 +60,11 @@ export default defineConfig({ jsMinifier: 'none', alias: { '@/modules': path.join(__dirname, '../src/modules'), + '@difizen/magent-flow': path.resolve( + __dirname, + '../../../web-packages/magent-flow/src', + ), + '@flow': path.resolve(__dirname, '../../../web-packages/magent-flow/src'), }, favicons: ['/favicon.ico'], }); diff --git a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx index 28d936d..71aca26 100644 --- a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx +++ b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx @@ -202,7 +202,7 @@ const AgentFlowComponent = forwardRef( width: '100%', border: '1px dashed #d9d9d9', padding: '6px', - zIndex, + // zIndex, }} type="link" size="small" @@ -240,7 +240,7 @@ const AgentFlowComponent = forwardRef( }, ); -export interface AgentConfigViewOption { +export interface AgentFlowViewOption { agentId: string; } @transient() @@ -252,7 +252,7 @@ export class AgentFlowView extends BaseView { @prop() agent: AgentModel; protected agentManager: AgentManager; constructor( - @inject(ViewOption) option: AgentConfigViewOption, + @inject(ViewOption) option: AgentFlowViewOption, @inject(AgentManager) agentManager: AgentManager, ) { super(); diff --git a/web-apps/ui/src/views/agent-flow/flow-dev-view.tsx b/web-apps/ui/src/views/agent-flow/flow-dev-view.tsx index e2a6173..a92d326 100644 --- a/web-apps/ui/src/views/agent-flow/flow-dev-view.tsx +++ b/web-apps/ui/src/views/agent-flow/flow-dev-view.tsx @@ -64,14 +64,6 @@ const AgentFlowDevComponent = forwardRef( {instance.chat && }
- {instance.hideChat && ( - - )}
); @@ -82,7 +74,7 @@ const AgentFlowDevComponent = forwardRef( @view(viewId) export class AgentFlowDevView extends AgentView { @prop() - hideChat = false; + hideChat = true; protected agentConfigManager: AgentConfigManager; diff --git a/web-apps/ui/src/views/agent-flow/index.less b/web-apps/ui/src/views/agent-flow/index.less index 5b11ca3..e8e2e9b 100644 --- a/web-apps/ui/src/views/agent-flow/index.less +++ b/web-apps/ui/src/views/agent-flow/index.less @@ -35,12 +35,12 @@ width: 55%; .magent-agent-flow { - > :first-child { - > :first-child { - box-shadow: var(--mana-ant-box-shadow-card); - z-index: 1; - } - } + // > :first-child { + // > :first-child { + // box-shadow: var(--mana-ant-box-shadow-card); + // z-index: 1; + // } + // } .react-flow { background-color: var(--mana-ant-color-bg-layout); @@ -53,7 +53,7 @@ min-width: 416px; width: 416px; background-color: var(--mana-color-bg-container); - box-shadow: var(--mana-ant-box-shadow-card); + box-shadow: var(--mana-ant-box-shadow-drawer-left); &-header { padding: 0 24px 0 6px; diff --git a/web-apps/ui/src/views/agent-flow/toolbar.tsx b/web-apps/ui/src/views/agent-flow/toolbar.tsx index 0021bf5..6848847 100644 --- a/web-apps/ui/src/views/agent-flow/toolbar.tsx +++ b/web-apps/ui/src/views/agent-flow/toolbar.tsx @@ -1,24 +1,37 @@ +import { MessageOutlined, SaveOutlined } from '@ant-design/icons'; import { useFlowStore } from '@difizen/magent-flow'; +import { useInject } from '@difizen/mana-app'; import { Button } from 'antd'; import classNames from 'classnames'; import yaml from 'js-yaml'; import React from 'react'; +import { AgentFlowDevView } from './flow-dev-view.js'; + export const Toolbar = (props: { classname?: string; style?: React.CSSProperties }) => { const { classname, style } = props; const { getFlow } = useFlowStore(); + const flowDevView = useInject(AgentFlowDevView); return (
- + {flowDevView.hideChat && ( + + )} */} - {/* chat.sendMessageStream(v)} /> */} instance.sendMessage(v)} />
diff --git a/web-packages/magent-flow/.eslintignore b/web-packages/magent-flow/.eslintignore new file mode 100644 index 0000000..e2dd15a --- /dev/null +++ b/web-packages/magent-flow/.eslintignore @@ -0,0 +1,3 @@ +**/dist/**/*.js +**/dist/**/*.cjs +**/dist/**/*.mjs diff --git a/web-packages/magent-flow/src/FormSchema/index.ts b/web-packages/magent-flow/src/FormSchema/index.ts index 51adf0b..b7261ab 100644 --- a/web-packages/magent-flow/src/FormSchema/index.ts +++ b/web-packages/magent-flow/src/FormSchema/index.ts @@ -1,3 +1,4 @@ +import { UUID } from '@flow/spec/uuid.js'; import { message } from 'antd'; import type { JSONSchema7, @@ -5,8 +6,6 @@ import type { JSONSchema7TypeName, } from 'json-schema'; -import { UUID } from '@/spec/uuid.js'; - export type OrderJSONSchema7 = JSONSchema7 & { order: number; }; diff --git a/web-packages/magent-flow/src/RefForm/index.tsx b/web-packages/magent-flow/src/RefForm/index.tsx index a9bbaf6..c882865 100644 --- a/web-packages/magent-flow/src/RefForm/index.tsx +++ b/web-packages/magent-flow/src/RefForm/index.tsx @@ -1,9 +1,8 @@ import { CaretRightOutlined } from '@ant-design/icons'; +import type { NodeDataType } from '@flow/interfaces/flow.js'; import { Button, Cascader, Collapse, Flex, Input, Select, Space, theme } from 'antd'; import React, { useEffect, useMemo, useState } from 'react'; -import type { NodeDataType } from '@/interfaces/flow.js'; - interface CascaderOptions { value: string; label: string; @@ -26,7 +25,7 @@ const getCascaderOptions = (node: NodeDataType) => { // 递归解析JSONSchema const parseSchema = (schema: any): CascaderOptions[] => { - console.log('🚀 ~ parseSchema ~ schema:', schema); + // console.log('🚀 ~ parseSchema ~ schema:', schema); const parsedOptions: CascaderOptions[] = []; for (const key in schema.properties) { diff --git a/web-packages/magent-flow/src/SchemaConfigForm/index.tsx b/web-packages/magent-flow/src/SchemaConfigForm/index.tsx index ad65dbf..6b975cf 100644 --- a/web-packages/magent-flow/src/SchemaConfigForm/index.tsx +++ b/web-packages/magent-flow/src/SchemaConfigForm/index.tsx @@ -7,13 +7,12 @@ import { CaretRightOutlined, MinusCircleOutlined, } from '@ant-design/icons'; +import { variableTypeOptions } from '@flow/FormSchema/index.js'; +import type { FormSchema, OrderJSONSchema7 } from '@flow/FormSchema/index.js'; import { Card, Checkbox, Collapse, Form, Input, Select, Space, theme } from 'antd'; import type { JSONSchema7 } from 'json-schema'; import React, { useState } from 'react'; -import { variableTypeOptions } from '@/FormSchema/index.js'; -import type { FormSchema, OrderJSONSchema7 } from '@/FormSchema/index.js'; - // import { // FormSchema, // OrderJSONSchema7, @@ -164,7 +163,6 @@ export const SchemaConfigForm = (props: { const propertiesKeys = Object.keys(schema.properties || {}); propertiesKeys.sort((a, b) => { const p = schema.properties as { [key: string]: OrderJSONSchema7 }; - console.log(p[a].order, p[b]?.order, '==order'); return (p[a]?.order || 999) - (p[b]?.order || 999); }); diff --git a/web-packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx b/web-packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx index ae4b320..3c65e42 100644 --- a/web-packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx @@ -2,7 +2,7 @@ import type { CascaderProps } from 'antd'; import { Cascader } from 'antd'; import React from 'react'; -import { classNames } from '@/utils/index.js'; +import { classNames } from '@flow/utils/index.js'; export const CascaderInNode = (props: CascaderProps) => { return ( diff --git a/web-packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx b/web-packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx index fe2bfb2..6e7d41a 100644 --- a/web-packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/OutputVariableTree/OutputVariable/index.tsx @@ -1,4 +1,4 @@ -import { capitalizeFirstLetter } from '@/utils/basic.js'; +import { capitalizeFirstLetter } from '@flow/utils/basic.js'; export const OutputVariable = (props: { name: string; type: string }) => { const { name, type } = props; diff --git a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx index 6d67748..c110db8 100644 --- a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/component-picker-block/index.tsx @@ -6,7 +6,7 @@ import type { TextNode } from 'lexical'; import React, { Fragment, memo, useCallback, useState } from 'react'; import ReactDOM from 'react-dom'; -import { useEventEmitterContextContext } from '@/context/event-emitter.js'; +import { useEventEmitterContextContext } from '@flow/context/event-emitter.js'; import { useBasicTypeaheadTriggerMatch } from '../../hooks.js'; import type { ExternalToolBlockType, VariableBlockType } from '../../types.js'; diff --git a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx index e1d5a5c..1f8a36c 100644 --- a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx @@ -1,7 +1,7 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { $insertNodes } from 'lexical'; -import { useEventEmitterContextContext } from '@/context/event-emitter.js'; +import { useEventEmitterContextContext } from '@flow/context/event-emitter.js'; import { textToEditorState } from '../utils.js'; diff --git a/web-packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx b/web-packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx index 26bebc4..de2a69f 100644 --- a/web-packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx @@ -1,7 +1,7 @@ import type { SelectProps } from 'antd'; import { Select } from 'antd'; -import { classNames } from '@/utils/index.js'; +import { classNames } from '@flow/utils/index.js'; export const SelectInNode = (props: SelectProps) => { return ( diff --git a/web-packages/magent-flow/src/components/ConditionForm/index.tsx b/web-packages/magent-flow/src/components/ConditionForm/index.tsx index 3c35ddf..19c9dd5 100644 --- a/web-packages/magent-flow/src/components/ConditionForm/index.tsx +++ b/web-packages/magent-flow/src/components/ConditionForm/index.tsx @@ -1,9 +1,8 @@ +import type { ConditionBranch } from '@flow/interfaces/flow.js'; import { Form } from 'antd'; import type { DefaultOptionType } from 'antd/es/cascader'; import { useEffect } from 'react'; -import type { ConditionBranch } from '@/interfaces/flow.js'; - import { SelectInNode } from '../AIBasic/SelectInNode//index.js'; import { ReferenceSelect } from '../ReferenceSelect/index.js'; @@ -17,8 +16,10 @@ export const ConditionForm = (props: { const compare = Form.useWatch('compare', form); useEffect(() => { - form.setFieldsValue(value.conditions[0]); - }, [form, value.conditions]); + if (value) { + form.setFieldsValue(value.conditions[0]); + } + }, [form, value, value?.conditions]); return ( { diff --git a/web-packages/magent-flow/src/components/Flow/keys.ts b/web-packages/magent-flow/src/components/Flow/keys.ts index abf603c..5749eb7 100644 --- a/web-packages/magent-flow/src/components/Flow/keys.ts +++ b/web-packages/magent-flow/src/components/Flow/keys.ts @@ -1,6 +1,6 @@ import { cloneDeep } from 'lodash'; -import isWrappedWithClass from '@/utils/wrappedClass.js'; +import isWrappedWithClass from '@flow/utils/wrappedClass.js'; export function handleUndo(e: KeyboardEvent, undo: any) { if (!isWrappedWithClass(e, 'noflow')) { diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/icons/agent.svg b/web-packages/magent-flow/src/components/FlowWithPanel/icons/agent.svg new file mode 100644 index 0000000..76381dc --- /dev/null +++ b/web-packages/magent-flow/src/components/FlowWithPanel/icons/agent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/icons/end.svg b/web-packages/magent-flow/src/components/FlowWithPanel/icons/end.svg new file mode 100644 index 0000000..fc045e1 --- /dev/null +++ b/web-packages/magent-flow/src/components/FlowWithPanel/icons/end.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/icons/ifelse.svg b/web-packages/magent-flow/src/components/FlowWithPanel/icons/ifelse.svg new file mode 100644 index 0000000..29178be --- /dev/null +++ b/web-packages/magent-flow/src/components/FlowWithPanel/icons/ifelse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/icons/knowledge.svg b/web-packages/magent-flow/src/components/FlowWithPanel/icons/knowledge.svg new file mode 100644 index 0000000..c294427 --- /dev/null +++ b/web-packages/magent-flow/src/components/FlowWithPanel/icons/knowledge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/icons/llm.svg b/web-packages/magent-flow/src/components/FlowWithPanel/icons/llm.svg new file mode 100644 index 0000000..91f0279 --- /dev/null +++ b/web-packages/magent-flow/src/components/FlowWithPanel/icons/llm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/icons/start.svg b/web-packages/magent-flow/src/components/FlowWithPanel/icons/start.svg new file mode 100644 index 0000000..f201e58 --- /dev/null +++ b/web-packages/magent-flow/src/components/FlowWithPanel/icons/start.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/icons/tool.svg b/web-packages/magent-flow/src/components/FlowWithPanel/icons/tool.svg new file mode 100644 index 0000000..406a243 --- /dev/null +++ b/web-packages/magent-flow/src/components/FlowWithPanel/icons/tool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx index e68272d..0f5159c 100644 --- a/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx +++ b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx @@ -1,9 +1,8 @@ +import { EventEmitterContextProvider } from '@flow/context/event-emitter.js'; +import type { NodeDataType } from '@flow/interfaces/flow.js'; +import { NodeTypeEnum } from '@flow/interfaces/flow.js'; import yaml from 'js-yaml'; -import { EventEmitterContextProvider } from '@/context/event-emitter.js'; -import type { NodeDataType } from '@/interfaces/flow.js'; -import { NodeTypeEnum } from '@/interfaces/flow.js'; - import Flow from '../Flow/index.js'; import { AgentNode } from '../Node/AgentNode/index.js'; import { EndNode } from '../Node/EndNode/index.js'; @@ -13,6 +12,24 @@ import { LLMNode } from '../Node/LLMNode/index.js'; import { StartNode } from '../Node/StartNode/index.js'; import { NodesPanel } from '../NodePanel/index.js'; +import agentIcon from './icons/agent.svg'; +import endIcon from './icons/end.svg'; +import ifelseIcon from './icons/ifelse.svg'; +import knowledgeIcon from './icons/knowledge.svg'; +import llmIcon from './icons/llm.svg'; +import startIcon from './icons/start.svg'; +import toolIcon from './icons/tool.svg'; + +const iconMap = { + start: startIcon, + end: endIcon, + llm: llmIcon, + knowledge: knowledgeIcon, + tool: toolIcon, + agent: agentIcon, + ifelse: ifelseIcon, +}; + const yamlContent = ` - id: 1 name: 开始节点 @@ -148,7 +165,7 @@ const yamlContent = ` - name: output type: string - id: 6 - name: Agent智能体 + name: 智能体 description: type: agent data: @@ -188,7 +205,9 @@ const yamlContent = ` export const NodeSchemaParser = (obj: Record) => { obj['config'] = obj['data']; + const type = obj['type']; obj['icon'] = + iconMap[type as keyof typeof iconMap] || 'https://mdn.alipayobjects.com/huamei_xbkogb/afts/img/A*PzmdRpvZz58AAAAAAAAAAAAADqarAQ/original'; delete obj['data']; @@ -230,7 +249,10 @@ export const FlowWithPanel = (props: { toolbar?: React.ReactNode }) => { return (
- +
diff --git a/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx b/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx index 441830e..88cca1b 100644 --- a/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx @@ -1,9 +1,9 @@ -import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper/index.js'; -import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; -import PromptEditor from '@/components/AIBasic/PromptEditor/index.js'; -import { ReferenceForm } from '@/components/ReferenceForm/index.js'; -import type { BasicSchema, NodeDataType } from '@/interfaces/flow.js'; -import { useFlowStore } from '@/stores/useFlowStore.js'; +import { CollapseWrapper } from '@flow/components/AIBasic/CollapseWrapper/index.js'; +import { OutputVariable } from '@flow/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; +import PromptEditor from '@flow/components/AIBasic/PromptEditor/index.js'; +import { ReferenceForm } from '@flow/components/ReferenceForm/index.js'; +import type { BasicSchema, NodeDataType } from '@flow/interfaces/flow.js'; +import { useFlowStore } from '@flow/stores/useFlowStore.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; diff --git a/web-packages/magent-flow/src/components/Node/CommonNode/index.tsx b/web-packages/magent-flow/src/components/Node/CommonNode/index.tsx index a2628f6..fe4a7eb 100644 --- a/web-packages/magent-flow/src/components/Node/CommonNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/CommonNode/index.tsx @@ -1,7 +1,7 @@ import { Collapse } from 'antd'; import React from 'react'; -import type { NodeDataType } from '@/interfaces/flow.js'; +import type { NodeDataType } from '@flow/interfaces/flow.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; diff --git a/web-packages/magent-flow/src/components/Node/EndNode/index.tsx b/web-packages/magent-flow/src/components/Node/EndNode/index.tsx index 9c3681b..607e1d9 100644 --- a/web-packages/magent-flow/src/components/Node/EndNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/EndNode/index.tsx @@ -1,8 +1,8 @@ -import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper/index.js'; -import PromptEditor from '@/components/AIBasic/PromptEditor/index.js'; -import { ReferenceForm } from '@/components/ReferenceForm/index.js'; -import type { BasicSchema, NodeDataType } from '@/interfaces/flow.js'; -import { useFlowStore } from '@/stores/useFlowStore.js'; +import { CollapseWrapper } from '@flow/components/AIBasic/CollapseWrapper/index.js'; +import PromptEditor from '@flow/components/AIBasic/PromptEditor/index.js'; +import { ReferenceForm } from '@flow/components/ReferenceForm/index.js'; +import type { BasicSchema, NodeDataType } from '@flow/interfaces/flow.js'; +import { useFlowStore } from '@flow/stores/useFlowStore.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; diff --git a/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx b/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx index 7a99001..efaf492 100644 --- a/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx @@ -1,6 +1,6 @@ -import { ConditionForm } from '@/components/ConditionForm/index.js'; -import type { NodeDataType, NodeType } from '@/interfaces/flow.js'; -import { useFlowStore } from '@/stores/useFlowStore.js'; +import { ConditionForm } from '@flow/components/ConditionForm/index.js'; +import type { NodeDataType, NodeType } from '@flow/interfaces/flow.js'; +import { useFlowStore } from '@flow/stores/useFlowStore.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; @@ -43,7 +43,7 @@ export const IfElseNode = (props: Props) => {
如果
{ setNode(data.id, (old) => ({ ...old, diff --git a/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx b/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx index b7c8376..4f15310 100644 --- a/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/KnowledgeNode/index.tsx @@ -1,12 +1,12 @@ import { PlusOutlined } from '@ant-design/icons'; import { Button, Modal } from 'antd'; -import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper/index.js'; -import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; -import { ReferenceForm } from '@/components/ReferenceForm/index.js'; -import type { BasicSchema, NodeDataType } from '@/interfaces/flow.js'; -import { useFlowStore } from '@/stores/useFlowStore.js'; -import { useKnowledgeStore } from '@/stores/useKnowledgeStore.js'; +import { CollapseWrapper } from '@flow/components/AIBasic/CollapseWrapper/index.js'; +import { OutputVariable } from '@flow/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; +import { ReferenceForm } from '@flow/components/ReferenceForm/index.js'; +import type { BasicSchema, NodeDataType } from '@flow/interfaces/flow.js'; +import { useFlowStore } from '@flow/stores/useFlowStore.js'; +import { useKnowledgeStore } from '@flow/stores/useKnowledgeStore.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; diff --git a/web-packages/magent-flow/src/components/Node/LLMNode/index.tsx b/web-packages/magent-flow/src/components/Node/LLMNode/index.tsx index ccd9387..a72df93 100644 --- a/web-packages/magent-flow/src/components/Node/LLMNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/LLMNode/index.tsx @@ -2,14 +2,14 @@ import { BarsOutlined } from '@ant-design/icons'; import { Button, InputNumber, Popover } from 'antd'; import { useEffect, useState } from 'react'; -import { CollapseWrapper } from '@/components/AIBasic/CollapseWrapper/index.js'; -import { OutputVariable } from '@/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; -import PromptEditor from '@/components/AIBasic/PromptEditor/index.js'; -import { SelectInNode } from '@/components/AIBasic/SelectInNode/index.js'; -import { ReferenceForm } from '@/components/ReferenceForm/index.js'; -import type { BasicSchema, NodeDataType } from '@/interfaces/flow.js'; -import { useFlowStore } from '@/stores/useFlowStore.js'; -import { useModelStore } from '@/stores/useModelStore.js'; +import { CollapseWrapper } from '@flow/components/AIBasic/CollapseWrapper/index.js'; +import { OutputVariable } from '@flow/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; +import PromptEditor from '@flow/components/AIBasic/PromptEditor/index.js'; +import { SelectInNode } from '@flow/components/AIBasic/SelectInNode/index.js'; +import { ReferenceForm } from '@flow/components/ReferenceForm/index.js'; +import type { BasicSchema, NodeDataType } from '@flow/interfaces/flow.js'; +import { useFlowStore } from '@flow/stores/useFlowStore.js'; +import { useModelStore } from '@flow/stores/useModelStore.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; diff --git a/web-packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx b/web-packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx index 71d7168..02a6d0f 100644 --- a/web-packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx +++ b/web-packages/magent-flow/src/components/Node/NodeWrapper/Status/index.tsx @@ -1,7 +1,7 @@ import { Popover, Tag } from 'antd'; import React from 'react'; -import { classNames } from '@/utils/basic.js'; +import { classNames } from '@flow/utils/basic.js'; export enum RunStatusEnum { Success = 'success', diff --git a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx index fbd4bf8..d3ab039 100644 --- a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx +++ b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx @@ -1,10 +1,9 @@ +import type { NodeDataType } from '@flow/interfaces/flow.js'; +import { classNames } from '@flow/utils/index.js'; import { Handle, Position } from '@xyflow/react'; import { Space } from 'antd'; import React from 'react'; -import type { NodeDataType } from '@/interfaces/flow.js'; -import { classNames } from '@/utils/index.js'; - type Props = { data: NodeDataType; selected: boolean; @@ -34,7 +33,7 @@ export const NodeWrapper = (props: { return (
diff --git a/web-packages/magent-flow/src/components/Node/StartNode/index.tsx b/web-packages/magent-flow/src/components/Node/StartNode/index.tsx index 4c6a425..5eb0866 100644 --- a/web-packages/magent-flow/src/components/Node/StartNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/StartNode/index.tsx @@ -1,7 +1,5 @@ -import { Collapse } from 'antd'; - -import { VariableForm } from '@/components/VariableForm/index.js'; -import type { NodeDataType } from '@/interfaces/flow.js'; +import { VariableForm } from '@flow/components/VariableForm/index.js'; +import type { NodeDataType } from '@flow/interfaces/flow.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; @@ -17,19 +15,15 @@ export const StartNode = (props: Props) => { return ( - - {/* */} - - { - console.log('qianyan', values); - }} - /> - + { + // + }} + /> ); }; diff --git a/web-packages/magent-flow/src/components/NodePanel/index.tsx b/web-packages/magent-flow/src/components/NodePanel/index.tsx index b7eece2..54c564f 100644 --- a/web-packages/magent-flow/src/components/NodePanel/index.tsx +++ b/web-packages/magent-flow/src/components/NodePanel/index.tsx @@ -1,8 +1,7 @@ +import type { NodeDataType } from '@flow/interfaces/flow.js'; import { Input } from 'antd'; import React from 'react'; -import type { NodeDataType } from '@/interfaces/flow.js'; - interface NodesPanelProps { /** * @title 模板节点配置 @@ -46,7 +45,7 @@ export const NodesPanel = (props: NodesPanelProps) => { )} {nodes.sort().map((node) => (
diff --git a/web-packages/magent-flow/src/components/ReferenceForm/index.tsx b/web-packages/magent-flow/src/components/ReferenceForm/index.tsx index 6c0a84f..3faed77 100644 --- a/web-packages/magent-flow/src/components/ReferenceForm/index.tsx +++ b/web-packages/magent-flow/src/components/ReferenceForm/index.tsx @@ -2,7 +2,7 @@ import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; import { Button, Form, Input, Space } from 'antd'; import { useEffect } from 'react'; -import type { BasicSchema, NodeType } from '@/interfaces/flow.js'; +import type { BasicSchema, NodeType } from '@flow/interfaces/flow.js'; import { CollapseWrapper } from '../AIBasic/CollapseWrapper/index.js'; import { ReferenceSelect } from '../ReferenceSelect/index.js'; diff --git a/web-packages/magent-flow/src/components/ReferenceSelect/index.tsx b/web-packages/magent-flow/src/components/ReferenceSelect/index.tsx index f4b94cb..efb849b 100644 --- a/web-packages/magent-flow/src/components/ReferenceSelect/index.tsx +++ b/web-packages/magent-flow/src/components/ReferenceSelect/index.tsx @@ -1,7 +1,7 @@ import { Input } from 'antd'; import type { DefaultOptionType } from 'antd/es/cascader'; -import type { SchemaValueType, ValueType } from '@/interfaces/flow.js'; +import type { SchemaValueType, ValueType } from '@flow/interfaces/flow.js'; import { CascaderInNode } from '../AIBasic/CascaderInNode/index.js'; import { SelectInNode } from '../AIBasic/SelectInNode/index.js'; diff --git a/web-packages/magent-flow/src/components/VariableForm/index.tsx b/web-packages/magent-flow/src/components/VariableForm/index.tsx index 187cb62..dbe92af 100644 --- a/web-packages/magent-flow/src/components/VariableForm/index.tsx +++ b/web-packages/magent-flow/src/components/VariableForm/index.tsx @@ -3,11 +3,10 @@ import { MinusCircleOutlined, PlusOutlined, } from '@ant-design/icons'; +import type { BasicSchema } from '@flow/interfaces/flow.js'; import { Button, Checkbox, Collapse, Form, Input, Space } from 'antd'; import React, { useEffect } from 'react'; -import type { BasicSchema } from '@/interfaces/flow.js'; - import { SelectInNode } from '../AIBasic/SelectInNode/index.js'; export interface VariableFormProps { diff --git a/web-packages/magent-flow/src/interfaces/flow.ts b/web-packages/magent-flow/src/interfaces/flow.ts index 04eff4f..d6e99a7 100644 --- a/web-packages/magent-flow/src/interfaces/flow.ts +++ b/web-packages/magent-flow/src/interfaces/flow.ts @@ -64,11 +64,11 @@ export interface NodeDataConfigType { outputs?: BasicSchema[]; } -// export interface NodeDataMetaType { -// name: string; -// icon?: string; -// description?: string; -// } +export interface NodeDataMetaType { + name: string; + icon?: string; + description?: string; +} export interface NodeDataType { id: string; diff --git a/web-packages/magent-flow/src/spec/node.test.ts b/web-packages/magent-flow/src/spec/node.test.ts index 02375ee..7cb78f7 100644 --- a/web-packages/magent-flow/src/spec/node.test.ts +++ b/web-packages/magent-flow/src/spec/node.test.ts @@ -149,7 +149,6 @@ describe('addField', () => { required: false, }); const got = input.log(); - console.log(got, '==got'); expect(got).toMatchSnapshot(); // expect(1).toBe(0); }); @@ -163,7 +162,6 @@ describe('addField', () => { description: 'this is a', required: false, }); - console.log(input.log(), 'log1'); input.addField({ pointer: '/a/b', // 指定属性路径,如 /a/b name: 'b', @@ -193,7 +191,6 @@ describe('addField', () => { required: true, }); const got = input.log(); - console.log(got); expect(got).toMatchSnapshot(); }); }); diff --git a/web-packages/magent-flow/src/spec/node.ts b/web-packages/magent-flow/src/spec/node.ts index 5b01977..f415454 100644 --- a/web-packages/magent-flow/src/spec/node.ts +++ b/web-packages/magent-flow/src/spec/node.ts @@ -2,8 +2,8 @@ import type { NodeDataConfigType, NodeDataMetaType, NodeDataType, -} from '@/interfaces/flow.js'; -import { NodeTypeEnum } from '@/interfaces/flow.js'; +} from '@flow/interfaces/flow.js'; +import { NodeTypeEnum } from '@flow/interfaces/flow.js'; import { FormSchema } from './FormSchema/index.js'; import { UUID } from './uuid.js'; diff --git a/web-packages/magent-flow/src/stores/useFlowStore.ts b/web-packages/magent-flow/src/stores/useFlowStore.ts index 037c32d..dcb7004 100644 --- a/web-packages/magent-flow/src/stores/useFlowStore.ts +++ b/web-packages/magent-flow/src/stores/useFlowStore.ts @@ -14,8 +14,8 @@ import { addEdge, applyEdgeChanges, applyNodeChanges } from '@xyflow/react'; import { cloneDeep } from 'lodash'; import { create } from 'zustand'; -import type { NodeType } from '@/interfaces/flow.js'; -import { cleanEdges, getNodeId } from '@/utils/reactflowUtils.js'; +import type { NodeType } from '@flow/interfaces/flow.js'; +import { cleanEdges, getNodeId } from '@flow/utils/reactflowUtils.js'; interface AdjacencyList { [key: number]: number[]; diff --git a/web-packages/magent-flow/src/stores/useKnowledgeStore.ts b/web-packages/magent-flow/src/stores/useKnowledgeStore.ts index 7c9c063..d2cbc69 100644 --- a/web-packages/magent-flow/src/stores/useKnowledgeStore.ts +++ b/web-packages/magent-flow/src/stores/useKnowledgeStore.ts @@ -1,6 +1,6 @@ import { create } from 'zustand'; -import type { BasicSchema } from '@/interfaces/flow.js'; +import type { BasicSchema } from '@flow/interfaces/flow.js'; export interface Knowledge { name: string; diff --git a/web-packages/magent-flow/src/stores/useModelStore.ts b/web-packages/magent-flow/src/stores/useModelStore.ts index 6326ef6..bda4463 100644 --- a/web-packages/magent-flow/src/stores/useModelStore.ts +++ b/web-packages/magent-flow/src/stores/useModelStore.ts @@ -1,7 +1,7 @@ import type React from 'react'; import { create } from 'zustand'; -import type { BasicSchema } from '@/interfaces/flow.js'; +import type { BasicSchema } from '@flow/interfaces/flow.js'; // 注册 模型选择和配置组件 提供onChange事件 export interface Model { diff --git a/web-packages/magent-flow/src/stores/useShortcutsStore.ts b/web-packages/magent-flow/src/stores/useShortcutsStore.ts index a7044ab..1c0c14f 100644 --- a/web-packages/magent-flow/src/stores/useShortcutsStore.ts +++ b/web-packages/magent-flow/src/stores/useShortcutsStore.ts @@ -1,6 +1,6 @@ import { create } from 'zustand'; -import { defaultShortcuts } from '@/constants/constant.js'; +import { defaultShortcuts } from '@flow/constants/constant.js'; export type shortcutsStoreType = { updateUniqueShortcut: (name: string, combination: string) => void; diff --git a/web-packages/magent-flow/src/stores/useUndoRedoStore.ts b/web-packages/magent-flow/src/stores/useUndoRedoStore.ts index 5e9da9a..7ce2fcb 100644 --- a/web-packages/magent-flow/src/stores/useUndoRedoStore.ts +++ b/web-packages/magent-flow/src/stores/useUndoRedoStore.ts @@ -56,7 +56,6 @@ export const useUndoRedoStore = create(() => ({ future = []; }, undo: () => { - console.log('🚀 ~ useUndoRedoStore ~ undo:'); const newState = useFlowStore.getState(); const pastLength = past?.length ?? 0; diff --git a/web-packages/magent-flow/tsconfig.json b/web-packages/magent-flow/tsconfig.json index e601a98..21e4afa 100644 --- a/web-packages/magent-flow/tsconfig.json +++ b/web-packages/magent-flow/tsconfig.json @@ -5,7 +5,7 @@ "outDir": "es", "declarationDir": "es", "paths": { - "@/*": ["./src/*"] + "@flow/*": ["./src/*"] } }, "types": ["jest"], From 7bcdcae0efa5445183d1547aeebcb70c8b53604f Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Thu, 29 Aug 2024 13:21:05 +0800 Subject: [PATCH 19/78] feat(ui): support error message --- .../modules/chat-message/ai-message-item.ts | 23 +++++- .../chat-message/peer-message-item-model.ts | 6 ++ .../ui/src/modules/chat-message/protocol.ts | 7 ++ .../chat/components/message/ai-message.tsx | 74 +++++++++++++------ .../views/chat/components/message/index.less | 32 +++++--- 5 files changed, 109 insertions(+), 33 deletions(-) diff --git a/web-apps/ui/src/modules/chat-message/ai-message-item.ts b/web-apps/ui/src/modules/chat-message/ai-message-item.ts index fba99a6..4190c9c 100644 --- a/web-apps/ui/src/modules/chat-message/ai-message-item.ts +++ b/web-apps/ui/src/modules/chat-message/ai-message-item.ts @@ -6,7 +6,13 @@ import type { AgentModel } from '../agent/agent-model.js'; import { AxiosClient } from '../axios-client/protocol.js'; import { ChatMessageItem } from './chat-message-item.js'; -import type { ChatEventChunk, ChatEventResult, ChatEventStep } from './protocol.js'; +import type { + ChatErrorInfo, + ChatEventChunk, + ChatEventError, + ChatEventResult, + ChatEventStep, +} from './protocol.js'; import { AnswerState, ChatMessageItemOption } from './protocol.js'; @transient() @@ -21,6 +27,9 @@ export class AIChatMessageItem extends ChatMessageItem { @prop() declare state: AnswerState; + @prop() + error: ChatErrorInfo; + constructor( @inject(ChatMessageItemOption) option: ChatMessageItemOption, @inject(AxiosClient) axios: AxiosClient, @@ -64,11 +73,21 @@ export class AIChatMessageItem extends ChatMessageItem { if (e.event === 'steps') { this.handleSteps(data as ChatEventStep); } + + if (e.event === 'error') { + this.handleError(data as ChatEventError); + } } appendChunk(e: ChatEventChunk) { this.content = `${this.content}${e.output}`; } + + handleError(e: ChatEventError) { + // {"error": {"error_msg": "The node type is not supported"}, "type": "error"} + this.error = e.error; + } + handleSteps(e: ChatEventStep) { // if (e.agent_id === this.agent?.id) { // this.content = this.content + `${e.output}`; @@ -76,6 +95,6 @@ export class AIChatMessageItem extends ChatMessageItem { } handleResult(e: ChatEventResult) { - // this.content = e.output; + this.content = e.output; } } diff --git a/web-apps/ui/src/modules/chat-message/peer-message-item-model.ts b/web-apps/ui/src/modules/chat-message/peer-message-item-model.ts index ff691fe..dc3debf 100644 --- a/web-apps/ui/src/modules/chat-message/peer-message-item-model.ts +++ b/web-apps/ui/src/modules/chat-message/peer-message-item-model.ts @@ -7,6 +7,7 @@ import { AxiosClient } from '../axios-client/protocol.js'; import { AIChatMessageItem } from './ai-message-item.js'; import type { ChatEventChunk, + ChatEventError, ChatEventResult, ChatEventStep, ChatEventStepQA, @@ -187,6 +188,10 @@ export class PeerChatMessageItem extends AIChatMessageItem { if (e.event === 'steps') { this.handleSteps(data as ChatEventStep); } + + if (e.event === 'error') { + this.handleError(data as ChatEventError); + } } override handleSteps(e: ChatEventStep): void { @@ -212,6 +217,7 @@ export class PeerChatMessageItem extends AIChatMessageItem { } override handleResult(e: ChatEventResult): void { + super.handleResult(e); this.currentStep = 4; } } diff --git a/web-apps/ui/src/modules/chat-message/protocol.ts b/web-apps/ui/src/modules/chat-message/protocol.ts index 22935e8..a01b2c3 100644 --- a/web-apps/ui/src/modules/chat-message/protocol.ts +++ b/web-apps/ui/src/modules/chat-message/protocol.ts @@ -116,6 +116,13 @@ export interface ChatEventChunk { output: string; type: 'token'; } +export interface ChatErrorInfo { + error_msg: string; +} +export interface ChatEventError { + error: ChatErrorInfo; + type: 'error'; +} export interface ChainItem { source: string; diff --git a/web-apps/ui/src/views/chat/components/message/ai-message.tsx b/web-apps/ui/src/views/chat/components/message/ai-message.tsx index 6052263..74fb5d3 100644 --- a/web-apps/ui/src/views/chat/components/message/ai-message.tsx +++ b/web-apps/ui/src/views/chat/components/message/ai-message.tsx @@ -4,7 +4,7 @@ import { LikeOutlined, LoadingOutlined, } from '@ant-design/icons'; -import { useInject, useObserve, ViewInstance } from '@difizen/mana-app'; +import { prop, useInject, useObserve, ViewInstance } from '@difizen/mana-app'; import classNames from 'classnames'; import copy from 'copy-to-clipboard'; import type { ReactNode } from 'react'; @@ -23,28 +23,45 @@ interface AIMessageProps { exchange: ChatMessageModel; } +export const AIMessageError = (props: AIMessageProps) => { + if (!props.message?.error?.error_msg) { + return null; + } + return ( +
+ ERROR: {props.message.error?.error_msg} +
+ ); +}; + export const AIMessageAddon = (props: AIMessageProps) => { const exchange = useObserve(props.exchange); - if (!exchange.tokenUsage && !exchange.responseTime) { - return null; + let content = null; + if (exchange.tokenUsage || exchange.responseTime) { + content = ( +
+ {exchange.tokenUsage && ( +
+ Total token: {exchange.tokenUsage.total_tokens} + Completion: {exchange.tokenUsage.completion_tokens} + Prompt: {exchange.tokenUsage.prompt_tokens} +
+ )} + {exchange.responseTime && ( +
+ 结束时间: {exchange.endTime?.format('YYYY-MM-DD HH:mm:ss')} + 耗时: {exchange.responseTime} +
+ )} +
+ ); } return ( -
- {exchange.tokenUsage && ( -
- Total token: {exchange.tokenUsage.total_tokens} - Completion: {exchange.tokenUsage.completion_tokens} - Prompt: {exchange.tokenUsage.prompt_tokens} -
- )} - {exchange.responseTime && ( -
- 结束时间: {exchange.endTime?.format('YYYY-MM-DD HH:mm:ss')} - 耗时: {exchange.responseTime} -
- )} -
+ <> + {content} + + ); }; @@ -53,14 +70,27 @@ export const AIMessageContent = (props: AIMessageProps) => { const content: ReactNode = message.content; if (!content) { return ( -
- +
+
+ +
+
); } else { return ( -
-
+
+
:first-child { width: 100%; } -} -.chat-message-ai-empty { - background-color: #f8f8fb; - border-radius: 8px; - width: 100%; -} + &-empty { + background-color: #f8f8fb; + border-radius: 8px; + width: 100%; + } -.chat-message-ai-receiving { - color: var(--mana-text-quaternary); - padding: 8px 16px; + &-receiving { + color: var(--mana-text-quaternary); + padding: 8px 16px; + } + + &-error { + // border: 1px solid var(--mana-ant-color-error); + + .chat-message-ai-content { + box-shadow: var(--mana-ant-box-shadow-tabs-overflow-bottom); + } + + .chat-message-addon-error { + padding: 4px 12px; + color: var(--mana-ant-color-error); + } + } } .chat-message-addon { From d29344365d40c8a3d69f5a5eae1cd6bd3f3c5875 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Thu, 29 Aug 2024 13:33:34 +0800 Subject: [PATCH 20/78] feat(ui): optmize error message --- .../ui/src/views/chat/components/message/ai-message.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web-apps/ui/src/views/chat/components/message/ai-message.tsx b/web-apps/ui/src/views/chat/components/message/ai-message.tsx index 74fb5d3..c1de3d3 100644 --- a/web-apps/ui/src/views/chat/components/message/ai-message.tsx +++ b/web-apps/ui/src/views/chat/components/message/ai-message.tsx @@ -77,7 +77,9 @@ export const AIMessageContent = (props: AIMessageProps) => { })} >
- + {message.state === AnswerState.RECEIVING && ( + + )}
@@ -90,7 +92,7 @@ export const AIMessageContent = (props: AIMessageProps) => { ['chat-message-ai-error']: message.error, })} > -
+
Date: Thu, 29 Aug 2024 13:41:28 +0800 Subject: [PATCH 21/78] feat(flow): padding style improvement --- .../magent-flow/src/components/Node/NodeWrapper/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx index d3ab039..54807ae 100644 --- a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx +++ b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx @@ -33,12 +33,12 @@ export const NodeWrapper = (props: { return (
{/* */} -
+
{icon && }
{name}
@@ -79,9 +79,9 @@ export const NodeWrapper = (props: { ))}
-
{description}
+
{description}
-
{children}
+
{children}
); }; From 5857a3153f1921c0c17b6168b2982c1a94722e83 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Thu, 29 Aug 2024 14:23:28 +0800 Subject: [PATCH 22/78] feat(ui): model selector performance improvement --- .../components/decimal-step/index.tsx | 0 web-apps/ui/src/modules/agent/agent-model.ts | 4 ---- web-apps/ui/src/modules/model/llm-model.ts | 7 +++++-- .../ui/src/modules/model/model-selector/index.tsx | 3 ++- web-apps/ui/src/modules/session/session-model.ts | 1 + .../components/character-setting/index.tsx | 6 +++--- .../agent-config/components/model-selector/index.tsx | 2 +- web-apps/ui/src/views/agent-config/view.tsx | 12 ++---------- web-apps/ui/src/views/agent-flow/index.less | 6 ++++++ web-apps/ui/src/views/agent-flow/toolbar.tsx | 6 +++++- 10 files changed, 25 insertions(+), 22 deletions(-) rename web-apps/ui/src/{views/agent-config => }/components/decimal-step/index.tsx (100%) diff --git a/web-apps/ui/src/views/agent-config/components/decimal-step/index.tsx b/web-apps/ui/src/components/decimal-step/index.tsx similarity index 100% rename from web-apps/ui/src/views/agent-config/components/decimal-step/index.tsx rename to web-apps/ui/src/components/decimal-step/index.tsx diff --git a/web-apps/ui/src/modules/agent/agent-model.ts b/web-apps/ui/src/modules/agent/agent-model.ts index 6311e87..bac7593 100644 --- a/web-apps/ui/src/modules/agent/agent-model.ts +++ b/web-apps/ui/src/modules/agent/agent-model.ts @@ -100,10 +100,6 @@ export class AgentModel extends AsyncModel { return true; } - updateOption(option: AgentModelOption) { - // TODO: - } - protected override fromMeta(option: AgentModelOption = this.option) { this.id = option.id; this.name = option.nickname; diff --git a/web-apps/ui/src/modules/model/llm-model.ts b/web-apps/ui/src/modules/model/llm-model.ts index 5d0d1df..5f2a73f 100644 --- a/web-apps/ui/src/modules/model/llm-model.ts +++ b/web-apps/ui/src/modules/model/llm-model.ts @@ -97,7 +97,10 @@ export class LLMModel implements LLMMeta { this.model_name = meta.model_name; } - updateMeta(meta: LLMMeta) { + updateMeta = (meta?: LLMMeta) => { + if (!meta) { + return; + } if (this.id !== meta.id) { this.id = meta.id; } @@ -110,7 +113,7 @@ export class LLMModel implements LLMMeta { if (this.model_name.join(',') !== meta.model_name.join(',')) { this.model_name = meta.model_name; } - } + }; toMeta = (): LLMMeta => { const meta: LLMMeta = { diff --git a/web-apps/ui/src/modules/model/model-selector/index.tsx b/web-apps/ui/src/modules/model/model-selector/index.tsx index 12fc207..96c037c 100644 --- a/web-apps/ui/src/modules/model/model-selector/index.tsx +++ b/web-apps/ui/src/modules/model/model-selector/index.tsx @@ -6,6 +6,7 @@ import type { FC } from 'react'; import { useState } from 'react'; import { forwardRef, useEffect } from 'react'; +import { DecimalStep } from '@/components/decimal-step/index.js'; import { LLMModel } from '@/modules/model/llm-model.js'; import { LLMProviderManager } from '@/modules/model/llm-provider-manager.js'; import { LLMIcon } from '@/modules/model/model-icon/index.js'; @@ -47,7 +48,7 @@ const TemperatureSlider: FC = ( const llm = useObserve(props.llm); const temperature = llm?.temperature; return ( - { +export const CharacterSetting = memo(function CharacterSetting() { const instance = useInject(ViewInstance); const agent = instance.agent; const prompt = agent.prompt; @@ -143,4 +143,4 @@ export const CharacterSetting = () => { />
); -}; +}); diff --git a/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx b/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx index 042ba2f..de32380 100644 --- a/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx +++ b/web-apps/ui/src/views/agent-config/components/model-selector/index.tsx @@ -3,11 +3,11 @@ import { useInject } from '@difizen/mana-app'; import { Button, Form, Select, Popover, Avatar } from 'antd'; import { forwardRef, useEffect } from 'react'; +import { DecimalStep } from '@/components/decimal-step/index.js'; import { LLMProviderManager } from '@/modules/model/llm-provider-manager.js'; import { LLMIcon } from '@/modules/model/model-icon/index.js'; import type { LLMMeta } from '@/modules/model/protocol.js'; -import { DecimalStep } from '../decimal-step/index.js'; import './index.less'; const clsPrefix = 'agent-config-model-selector'; diff --git a/web-apps/ui/src/views/agent-config/view.tsx b/web-apps/ui/src/views/agent-config/view.tsx index df86f07..d67c420 100644 --- a/web-apps/ui/src/views/agent-config/view.tsx +++ b/web-apps/ui/src/views/agent-config/view.tsx @@ -51,16 +51,8 @@ const AgentConfigViewComponent = forwardRef(
模型
{ - if (meta) { - instance.agent.llm?.updateMeta(meta); - } - }} - onConfigChanged={(meta) => { - if (meta) { - instance.agent.llm?.updateMeta(meta); - } - }} + onChange={instance.agent.llm?.updateMeta} + onConfigChanged={instance.agent.llm?.updateMeta} />
{flowDevView.hideChat && ( - -
- ); -}); diff --git a/web-apps/ui/src/views/agent-config/view.tsx b/web-apps/ui/src/views/agent-config/view.tsx index d67c420..ef7ae37 100644 --- a/web-apps/ui/src/views/agent-config/view.tsx +++ b/web-apps/ui/src/views/agent-config/view.tsx @@ -52,7 +52,6 @@ const AgentConfigViewComponent = forwardRef(
( nodeId: string; llmParam: BasicSchema[]; }) => { - const onChange = (val: LLMMeta) => { + const onChange = (val?: LLMMeta) => { + if (!val) { + return; + } setNode(nodeId, (old) => ({ ...old, data: { From a86a6918cc00657766dd6d2d17ce97ae8cb9c9a5 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Thu, 29 Aug 2024 15:01:58 +0800 Subject: [PATCH 24/78] fix(ui): au until api migrate --- README.md | 2 +- packages/magent-ui/src/magent_ui/routers/common/router.py | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 555e904..d150bdc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # magent -为智能体研发提供专业产品方案 +智能体研发产品方案 ## magent-ui diff --git a/packages/magent-ui/src/magent_ui/routers/common/router.py b/packages/magent-ui/src/magent_ui/routers/common/router.py index 88c3a12..5da91e8 100644 --- a/packages/magent-ui/src/magent_ui/routers/common/router.py +++ b/packages/magent-ui/src/magent_ui/routers/common/router.py @@ -1,9 +1,5 @@ -import asyncio -import enum -import json -from typing import AsyncIterable, List from fastapi import APIRouter -from agentuniverse_product.service.util.agent_util import is_component_id_unique +from agentuniverse_product.base.util.common_util import is_component_id_unique router = APIRouter() common_router = router From af2d2dd166e6172dc0edb511d181279d044e37e4 Mon Sep 17 00:00:00 2001 From: "xujianfeng.xjf" Date: Thu, 29 Aug 2024 15:34:49 +0800 Subject: [PATCH 25/78] feat: add flowdata init&output --- .../src/views/agent-flow/agent-flow-view.tsx | 44 ++- .../ui/src/views/agent-flow/flow-utils.ts | 44 +++ .../agent-flow/flow-with-tabs/icons/agent.svg | 1 + .../agent-flow/flow-with-tabs/icons/end.svg | 1 + .../flow-with-tabs/icons/ifelse.svg | 1 + .../flow-with-tabs/icons/knowledge.svg | 1 + .../agent-flow/flow-with-tabs/icons/llm.svg | 1 + .../agent-flow/flow-with-tabs/icons/start.svg | 1 + .../agent-flow/flow-with-tabs/icons/tool.svg | 1 + .../views/agent-flow/flow-with-tabs/index.tsx | 249 ++++++++++++ web-apps/ui/src/views/agent-flow/toolbar.tsx | 23 +- .../magent-flow/src/FormSchema/index.ts | 330 ---------------- web-packages/magent-flow/src/RefForm/index.md | 31 -- .../magent-flow/src/RefForm/index.tsx | 290 -------------- .../magent-flow/src/SchemaConfigForm/index.md | 29 -- .../src/SchemaConfigForm/index.tsx | 367 ------------------ .../magent-flow/src/components/Flow/index.tsx | 63 +-- .../src/components/FlowWithPanel/index.tsx | 38 +- .../FlowWithPanel/nodeTemplate.yaml | 171 -------- .../src/components/Node/IfElseNode/index.tsx | 4 +- .../src/components/Node/LLMNode/index.tsx | 7 +- .../magent-flow/src/components/Node/index.tsx | 8 + .../src/components/RefForm/index.md | 31 -- web-packages/magent-flow/src/index.ts | 9 +- .../magent-flow/src/interfaces/flow.ts | 2 +- .../magent-flow/src/spec/FormSchema/index.ts | 328 ---------------- .../src/spec/__snapshots__/node.test.ts.snap | 65 ---- .../magent-flow/src/spec/node.test.ts | 196 ---------- web-packages/magent-flow/src/spec/node.ts | 83 ---- .../magent-flow/src/spec/test-jsonschema.json | 87 ----- web-packages/magent-flow/src/spec/uuid.ts | 21 - .../magent-flow/src/stores/useFlowStore.ts | 18 +- 32 files changed, 427 insertions(+), 2118 deletions(-) create mode 100644 web-apps/ui/src/views/agent-flow/flow-utils.ts create mode 100644 web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/agent.svg create mode 100644 web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/end.svg create mode 100644 web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/ifelse.svg create mode 100644 web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/knowledge.svg create mode 100644 web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/llm.svg create mode 100644 web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/start.svg create mode 100644 web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/tool.svg create mode 100644 web-apps/ui/src/views/agent-flow/flow-with-tabs/index.tsx delete mode 100644 web-packages/magent-flow/src/FormSchema/index.ts delete mode 100644 web-packages/magent-flow/src/RefForm/index.md delete mode 100644 web-packages/magent-flow/src/RefForm/index.tsx delete mode 100644 web-packages/magent-flow/src/SchemaConfigForm/index.md delete mode 100644 web-packages/magent-flow/src/SchemaConfigForm/index.tsx delete mode 100644 web-packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml delete mode 100644 web-packages/magent-flow/src/components/RefForm/index.md delete mode 100644 web-packages/magent-flow/src/spec/FormSchema/index.ts delete mode 100644 web-packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap delete mode 100644 web-packages/magent-flow/src/spec/node.test.ts delete mode 100644 web-packages/magent-flow/src/spec/node.ts delete mode 100644 web-packages/magent-flow/src/spec/test-jsonschema.json delete mode 100644 web-packages/magent-flow/src/spec/uuid.ts diff --git a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx index 9882389..073a8bd 100644 --- a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx +++ b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx @@ -1,13 +1,9 @@ import { DeleteOutlined } from '@ant-design/icons'; import type { BasicSchema } from '@difizen/magent-flow'; -import { - FlowWithPanel, - useFlowStore, - useKnowledgeStore, - useModelStore, -} from '@difizen/magent-flow'; +import { useFlowStore, useKnowledgeStore, useModelStore } from '@difizen/magent-flow'; import { BaseView, inject, prop, view, ViewOption, transient } from '@difizen/mana-app'; import { Button } from 'antd'; +import yaml from 'js-yaml'; import { forwardRef, useEffect, useState } from 'react'; import { AgentManager } from '@/modules/agent/agent-manager.js'; @@ -22,6 +18,8 @@ import { KnowledgeModalComponent, } from '../agent-config/knowledge-modal/modal.js'; +import { InitEdgeParser, InitNodeParser } from './flow-utils.js'; +import { FlowWithTabs } from './flow-with-tabs/index.js'; import { Toolbar } from './toolbar.js'; const viewId = 'magent-agent-flow'; @@ -30,7 +28,7 @@ const AgentFlowComponent = forwardRef( function AgentConfigViewComponent(props, ref) { const { setModelSelector } = useModelStore(); const { setKnowledgeSelector } = useKnowledgeStore(); - const { setNode } = useFlowStore(); + const { setNode, initFlow } = useFlowStore(); useEffect(() => { // 注册 flow 中模型选择 @@ -175,13 +173,15 @@ const AgentFlowComponent = forwardRef(
@@ -224,9 +224,31 @@ const AgentFlowComponent = forwardRef( setKnowledgeSelector(Ele2 as any); }, [setKnowledgeSelector, setModelSelector, setNode]); + useEffect(() => { + const mockGraph = localStorage.getItem('magent_flow_testdata'); + if (!mockGraph) { + return; + } + const graph = yaml.load(mockGraph); + const nodes = graph.nodes.map((n) => { + return InitNodeParser(n); + }); + + const edges = graph.edges.map((e) => { + return InitEdgeParser(e); + }); + + // 获取 yaml 初始化 flow + initFlow({ + nodes: [...nodes], + edges: [...edges], + }); + console.log('🚀 ~ AgentConfigViewComponent ~ initFlow:'); + }, [initFlow]); + return (
- { + const obj: any = node.data; + obj['position'] = node.position; + obj['data'] = obj['config']; + + delete obj['config']; + delete obj['icon']; + return obj as NodeType; +}; + +export const OutputEdgeParser = (edge: Edge) => { + return { + id: edge.id, + target_handler: edge.targetHandle, + source_handler: edge.sourceHandle, + source_node_id: edge.source, + target_node_id: edge.target, + } as Edge; +}; + +export const InitNodeParser = (node: NodeType) => { + node['config'] = node['data']; + delete node['data']; + const obj: NodeType = { + id: node.id, + type: node.type, + position: node.position, + data: { ...node }, + }; + return obj; +}; + +export const InitEdgeParser = (edge: Edge) => { + const obj: Edge = { + id: edge.id, + targetHandle: edge.target_handler, + sourceHandle: edge.source_handler, + source: edge.source_node_id, + target: edge.target_node_id, + }; + return obj; +}; diff --git a/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/agent.svg b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/agent.svg new file mode 100644 index 0000000..76381dc --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/agent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/end.svg b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/end.svg new file mode 100644 index 0000000..fc045e1 --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/end.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/ifelse.svg b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/ifelse.svg new file mode 100644 index 0000000..29178be --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/ifelse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/knowledge.svg b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/knowledge.svg new file mode 100644 index 0000000..c294427 --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/knowledge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/llm.svg b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/llm.svg new file mode 100644 index 0000000..91f0279 --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/llm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/start.svg b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/start.svg new file mode 100644 index 0000000..f201e58 --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/start.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/tool.svg b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/tool.svg new file mode 100644 index 0000000..406a243 --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/flow-with-tabs/icons/tool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/views/agent-flow/flow-with-tabs/index.tsx b/web-apps/ui/src/views/agent-flow/flow-with-tabs/index.tsx new file mode 100644 index 0000000..5998451 --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/flow-with-tabs/index.tsx @@ -0,0 +1,249 @@ +import type { NodeDataType } from '@difizen/magent-flow'; +import { + NodeTypeEnum, + StartNode, + EndNode, + KnowledgeNode, + LLMNode, + IfElseNode, + AgentNode, + NodesPanel, + Flow, + useFlowStore, +} from '@difizen/magent-flow'; +import { Tabs } from 'antd'; +import yaml from 'js-yaml'; + +import agentIcon from './icons/agent.svg'; +import endIcon from './icons/end.svg'; +import ifelseIcon from './icons/ifelse.svg'; +import knowledgeIcon from './icons/knowledge.svg'; +import llmIcon from './icons/llm.svg'; +import startIcon from './icons/start.svg'; +import toolIcon from './icons/tool.svg'; + +const iconMap = { + start: startIcon, + end: endIcon, + llm: llmIcon, + knowledge: knowledgeIcon, + tool: toolIcon, + agent: agentIcon, + ifelse: ifelseIcon, +}; + +const templateNodeYaml = ` +- id: 1 + name: 开始节点 + description: 工作流的起始节点,用于设定启动工作流需要的信息 + type: start + data: + outputs: + - name: user_input + type: string + description: 用户本轮对话输入内容 +- id: 2 + position: + x: 200 + y: 100 + name: 结束节点 + description: 工作流的最终节点,用于返回工作流运行后的结果信息 + type: end + data: + inputs: + input_param: + - name: response + type: string + value: + type: reference + prompt: + name: response + type: string + description: 输出内容 + value: + type: reference + content: '{{response}}' + outputs: + - name: output + type: string +- id: 3 + name: 大模型节点 + description: 调用大语言模型,使用变量和提示词生成回复 + type: llm + data: + inputs: + input_param: + - name: input + description: + type: string + value: + type: reference + - name: background + description: + type: string + value: + type: reference + llm_param: + - type: string + name: id + value: + type: value + content: qwen_llm + - type: string + name: model_name + value: + content: qwen-max + type: value + - type: string + name: temperature + value: + content: '0.7' + type: value + - type: string + name: prompt + value: + type: value + content: | + 你是一位精通信息分析的ai助手。你的目标是使用中文结合查询的背景信息及你所拥有的知识回答用户提出的问题。 + 你需要遵守的规则是: + 1. 必须使用中文结合查询的背景信息结合你所拥有的知识回答用户提出的问题。 + 2. 结构化答案生成,必要时通过空行提升阅读体验。 + 3. 不采用背景信息中的错误信息。 + 4. 要考虑答案和问题的相关性,不做对问题没有帮助的回答。 + 5. 详尽回答问题,重点突出,不过多花哨词藻。 + 6. 不说模糊的推测。 + 7. 尽量多的使用数值类信息。 + + 背景信息是: + {{background}} + + 开始! + 需要回答的问题是: {{input}} + outputs: + - type: string + name: output +- id: 4 + name: 知识库 + description: + type: knowledge + data: + inputs: + knowledge_param: + - type: string + name: id + - type: string + name: top_k + value: + type: value + content: '2' + input_param: + - type: string + name: query # 自然语言的知识库query + value: + type: reference + outputs: + - name: output + type: string +- id: 5 + name: 工具 + description: + type: tool + position: + x: 500 + y: 100 + data: + inputs: + tool_param: + - type: string + name: id + value: google_search + input_param: + - type: string + name: input + value: + type: value + content: 'output' + outputs: + - name: output + type: string +- id: 6 + name: 智能体 + description: + type: agent + data: + inputs: + agent_param: + - type: string + name: id + value: demo_rag_agent + input_param: + - type: string + name: input + value: + type: reference + + outputs: + - name: output + type: string +- id: 7 + name: 条件判断 + description: + type: ifelse + data: + inputs: + branches: + - name: branch-1 + conditions: + - compare: equal + left: + type: string + value: + type: reference + right: # blank 没有right + type: string # 只有 if 和 else,branch-1和branch-default + value: + type: reference +`; + +export const NodeSchemaParser = (obj: Record) => { + obj['config'] = obj['data']; + const type = obj['type']; + obj['icon'] = + iconMap[type as keyof typeof iconMap] || + 'https://mdn.alipayobjects.com/huamei_xbkogb/afts/img/A*PzmdRpvZz58AAAAAAAAAAAAADqarAQ/original'; + + delete obj['data']; +}; + +const nodeTypes = { + [NodeTypeEnum.Start]: StartNode, + [NodeTypeEnum.End]: EndNode, + [NodeTypeEnum.LLM]: LLMNode, + [NodeTypeEnum.Knowledge]: KnowledgeNode, + [NodeTypeEnum.IfElse]: IfElseNode, + [NodeTypeEnum.Tool]: IfElseNode, + [NodeTypeEnum.Agent]: AgentNode, +}; + +export const FlowWithTabs = (props: { toolbar?: React.ReactNode }) => { + const { toolbar } = props; + const templateNodes = yaml.load(templateNodeYaml); + (templateNodes as Record[]).forEach((item) => { + NodeSchemaParser(item); + }); + + return ( +
+ + + + + + + +
+ ); +}; diff --git a/web-apps/ui/src/views/agent-flow/toolbar.tsx b/web-apps/ui/src/views/agent-flow/toolbar.tsx index db3b39a..d0ffba0 100644 --- a/web-apps/ui/src/views/agent-flow/toolbar.tsx +++ b/web-apps/ui/src/views/agent-flow/toolbar.tsx @@ -1,17 +1,20 @@ import { MessageOutlined, SaveOutlined } from '@ant-design/icons'; +import type { NodeType } from '@difizen/magent-flow'; import { useFlowStore } from '@difizen/magent-flow'; import { useInject } from '@difizen/mana-app'; -import { Button } from 'antd'; +import { Button, message } from 'antd'; import classNames from 'classnames'; import yaml from 'js-yaml'; import React from 'react'; import { AgentFlowDevView } from './flow-dev-view.js'; +import { OutputEdgeParser, OutputNodeParser } from './flow-utils.js'; export const Toolbar = (props: { classname?: string; style?: React.CSSProperties }) => { const { classname, style } = props; const { getFlow } = useFlowStore(); const flowDevView = useInject(AgentFlowDevView); + return (
} onClick={() => { - const flow = getFlow(); - const save_yaml = yaml.dump(flow); - // console.log('🚀 ~ Toolbar ~ flow:', save_yaml); + const flow = JSON.parse(JSON.stringify(getFlow())); + const nodes = flow.nodes.map((node) => { + return OutputNodeParser(node as NodeType); + }); + const edges = flow.edges.map((edge) => { + return OutputEdgeParser(edge); + }); + const graph = { + nodes, + edges, + }; + + const graph_yaml = yaml.dump(graph); + localStorage.setItem('magent_flow_testdata', graph_yaml); + message.success('保存成功'); }} > 保存 diff --git a/web-packages/magent-flow/src/FormSchema/index.ts b/web-packages/magent-flow/src/FormSchema/index.ts deleted file mode 100644 index b7261ab..0000000 --- a/web-packages/magent-flow/src/FormSchema/index.ts +++ /dev/null @@ -1,330 +0,0 @@ -import { UUID } from '@flow/spec/uuid.js'; -import { message } from 'antd'; -import type { - JSONSchema7, - JSONSchema7Definition, - JSONSchema7TypeName, -} from 'json-schema'; - -export type OrderJSONSchema7 = JSONSchema7 & { - order: number; -}; - -export interface CascaderOptions { - value: string; - label: string; - children?: CascaderOptions[]; -} - -/** - * 声明输入的表单数据格式 - * 表单内容 - */ -export class FormSchema { - uuid = UUID.getInstance().uniqueID(); - - jsonschema: JSONSchema7 = { - $id: this.uuid, - type: 'object', - properties: {}, - required: [], - }; - - constructor(schema: JSONSchema7) { - Object.assign(this.jsonschema, schema); - } - /** - * 获取指定路径的属性 - * 方便添加属性 - * /a/b/c/ - * @param pointer - * @returns - */ - getSchemaByPoint(pointer: string) { - if (pointer === '/' || pointer === '') { - return this.jsonschema; - } - - let pointers = pointer.split('/'); - if (pointers[0] !== '') { - throw new Error('invalid pointer'); - } - pointers = pointers.slice(1); - - // base是一个object模式 - let schema = this.jsonschema; - while (pointers.length > 0) { - const pointer = pointers.shift(); - if (pointer === undefined) { - throw new Error('invalid pointer'); - } - if (schema) { - if (schema.type === 'object') { - if (schema?.properties?.[pointer]) { - // 有就递归下沉 - schema = schema.properties[pointer] as JSONSchema7; - } else { - // 没有属性就添加 - schema!.properties![pointer] = {}; - return schema!.properties![pointer]; - } - } else if (schema?.type === 'array') { - if (schema?.items) { - const index = parseInt(pointer); - if (Array.isArray(schema.items)) { - schema = schema.items[index] as JSONSchema7; - } else { - schema = schema.items as JSONSchema7; - } - } - } - } - } - return schema; - } - - private randommName = () => { - return ( - 'RandaomName__-' + - Math.random().toString(36).substring(2, 15) + - Math.random().toString(36).substring(2, 15) - ); - }; - - isRandomName = (name: string) => { - return name.startsWith('RandaomName__-'); - }; - - /** - * 动态表单添加属性 - * @param property - * @returns - */ - addField = (options: { - pointer: string; // 指定属性路径,如 /a/b - name?: string; - type: JSONSchema7TypeName; - description: string; - required: boolean; - }) => { - const { pointer, name = this.randommName(), type, description, required } = options; - if (typeof this.jsonschema !== 'boolean') { - const schema = this.getSchemaByPoint(pointer); - if (schema.type === 'array') { - // 如果存在属性 - if (!schema?.items) { - schema.items = { - type: type, - description, - }; - } else if (!Array.isArray(schema?.items)) { - const items = schema.items as JSONSchema7Definition; - schema.items = [ - items, - { - type: type, - description, - }, - ]; - } else if (Array.isArray(schema?.items)) { - schema.items.push({ - type: type, - description, - }); - } - } else if (schema?.type === 'object') { - // 使用order 记录顺序 - let order = 0; - Object.entries(schema.properties || {}).forEach(([, val]) => { - const v = val as OrderJSONSchema7; - if (v?.order) { - order = v?.order > order ? v?.order : order; - } - }); - - (schema.properties![name] as OrderJSONSchema7) = { - type: type, - description, - order: order + 1, - }; - if (type === 'object') { - schema.properties![name].properties = {}; - } - } else { - schema.type = type; - schema.description = description; - } - if (required) { - // 如果是object的话,require在当前位置添加 - if (schema.type === 'object') { - if (!schema.required) { - schema.required = []; - } - schema.required = [...schema.required, name]; - } else { - // 在父级添加 - const parentPointer = pointer.split('/').slice(0, -1).join('/'); - const parentSchema = this.getSchemaByPoint(parentPointer); - - if (!parentSchema.required) { - parentSchema.required = []; - } - parentSchema.required = [...parentSchema.required, name]; - } - } - } - return false; - }; - - /** - * 动态表单更新属性 - * @param property - * @returns - */ - updateField = (options: { - pointer: string; // 指定属性路径,如 /a/b - key: 'variableName' | 'variableType' | 'description' | 'required'; - value: any; - currentVariableName: string; - }) => { - const { pointer, key, value, currentVariableName } = options; - if (typeof this.jsonschema !== 'boolean') { - const schema = this.getSchemaByPoint(pointer); - if (schema.type === 'object') { - if (schema.properties) { - if (key === 'variableName') { - const old = schema.properties?.[currentVariableName]; - if (value !== currentVariableName) { - schema.properties[value] = old; - delete schema.properties[currentVariableName]; - } else { - message.info('变量名不能和已有变量名相同'); - return false; - } - return true; - } - if (key === 'variableType') { - if ((schema.properties[currentVariableName] as JSONSchema7).type) { - // 处理数组类型 - if (value.startsWith('Array<')) { - const t = ( - value.replace('Array<', '').replace('>', '') as string - ).toLocaleLowerCase(); - schema.properties[currentVariableName].type = 'array'; - schema.properties[currentVariableName].items = { - type: t, - }; - if (t === 'object') { - schema.properties[currentVariableName].items.properties = {}; - } - return true; - } - if (value === 'object') { - schema.properties[currentVariableName].type = value; - schema.properties[currentVariableName].properties = {}; - return true; - } - - // 基础类型 - schema.properties[currentVariableName].type = value; - delete schema.properties[currentVariableName].items; - delete schema.properties[currentVariableName].properties; - - return true; - } - } - if (key === 'description') { - if (schema.properties[currentVariableName] as JSONSchema7) { - schema.properties[currentVariableName].description = value; - return true; - } - } - if (key === 'required') { - if (!this.isRandomName(currentVariableName)) { - if (schema.properties[currentVariableName]) { - if (!schema.required) { - schema.required = []; - } - if (value) { - if (!schema.required?.includes(value)) { - schema.required?.push(currentVariableName); - } - } else { - if (schema.required?.includes(currentVariableName)) { - schema.required = schema.required.filter( - (item) => item !== currentVariableName, - ); - } - } - - return true; - } - } - } - } - } - } - return false; - }; - - updateSchema(schema: JSONSchema7) { - Object.assign(this.jsonschema, schema); - } - - log() { - return JSON.stringify(this.jsonschema, null, 4); - } -} - -export const variableTypeOptions: { - label: string; - value: - | JSONSchema7TypeName - | 'Array' - | 'Array' - | 'Array' - | 'Array' - | 'Array'; -}[] = [ - { - label: 'String', - value: 'string', - }, - { - label: 'Integer', - value: 'integer', - }, - { - label: 'Boolean', - value: 'boolean', - }, - { - label: 'Number', - value: 'number', - }, - { - label: 'Object', - value: 'object', - }, - - { - label: 'Array', - value: 'Array', - }, - { - label: 'Array', - value: 'Array', - }, - { - label: 'Array', - value: 'Array', - }, - { - label: 'Array', - value: 'Array', - }, - { - label: 'Array', - value: 'Array', - }, -]; diff --git a/web-packages/magent-flow/src/RefForm/index.md b/web-packages/magent-flow/src/RefForm/index.md deleted file mode 100644 index d2676dc..0000000 --- a/web-packages/magent-flow/src/RefForm/index.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: RefForm -group: { title: 'Schema', order: 2 } -toc: menu -order: 1 -demo: { cols: 2 } ---- - -## 基本用法 - -> 渲染输入参数表单,支持传入节点引用数据 - -```jsx -import React from 'react'; -import { RefForm, FormSchema, StartNode } from '@alipay/ai-workflow'; - -const startNode = new StartNode(); -startNode.config.inputs.updateSchema({ - type: 'object', - properties: { - name: { - type: 'string', - title: '姓名', - }, - }, -}); - -export default () => Hi, bigfish; -``` - - diff --git a/web-packages/magent-flow/src/RefForm/index.tsx b/web-packages/magent-flow/src/RefForm/index.tsx deleted file mode 100644 index c882865..0000000 --- a/web-packages/magent-flow/src/RefForm/index.tsx +++ /dev/null @@ -1,290 +0,0 @@ -import { CaretRightOutlined } from '@ant-design/icons'; -import type { NodeDataType } from '@flow/interfaces/flow.js'; -import { Button, Cascader, Collapse, Flex, Input, Select, Space, theme } from 'antd'; -import React, { useEffect, useMemo, useState } from 'react'; - -interface CascaderOptions { - value: string; - label: string; - children?: CascaderOptions[]; -} - -/** - * 把jsonschema 转成cascader的options - */ -const getCascaderOptions = (node: NodeDataType) => { - const jsonSchema = node.config?.inputs?.jsonschema; - - const options: CascaderOptions[] = [ - { - label: `${node.name}`, - value: node?.name, - children: [], - }, - ]; - - // 递归解析JSONSchema - const parseSchema = (schema: any): CascaderOptions[] => { - // console.log('🚀 ~ parseSchema ~ schema:', schema); - const parsedOptions: CascaderOptions[] = []; - - for (const key in schema.properties) { - if (Object.hasOwn(schema.properties, key)) { - const type = schema.properties[key]?.type; - const label = `${key}-${type}`; - if (type === 'object') { - const childOptions: CascaderOptions[] = parseSchema(schema.properties[key]); - parsedOptions.push({ - value: key, - label: label, - children: childOptions, - }); - } else { - parsedOptions.push({ - value: key, - label: label, - }); - } - } - } - return parsedOptions; - }; - - if (jsonSchema && typeof jsonSchema === 'object') { - for (const key in jsonSchema.properties) { - if (Object.hasOwn(jsonSchema.properties, key)) { - const type = jsonSchema.properties[key]?.type; - const label = `${key}-${type}`; - - const rootOptions: CascaderOptions[] = options[0]! - .children as CascaderOptions[]; - - if (type === 'object') { - const childOptions: CascaderOptions[] = parseSchema( - jsonSchema.properties[key], - ); - rootOptions.push({ - value: key, - label: label, - children: childOptions, - }); - } else { - rootOptions.push({ - value: key, - label: label, - }); - } - } - } - } - - return options; -}; - -interface ParameterValue { - variableName: string; - variableType: 'ref' | 'input'; - variableValue: string | string[]; -} - -const Parameter = (props: { - flowNodes?: NodeDataType[]; - onChange?: (values: ParameterValue) => void; - values?: ParameterValue; -}) => { - const { flowNodes = [], onChange } = props; - - const [value, setValue] = useState({ - variableName: '', - variableType: 'ref', - variableValue: '', - }); - - const options: CascaderOptions[] = useMemo(() => { - let opt = [] as CascaderOptions[]; - flowNodes.forEach((v) => { - opt = [...opt, ...getCascaderOptions(v)]; - }); - return opt; - }, [flowNodes]); - - useEffect(() => { - onChange?.(value); - }, [value]); - - useEffect(() => { - if (props.values) { - setValue(props.values); - } - }, [props.values]); - - return ( - - { - setValue((s) => { - return { - ...s, - variableName: v.target.value, - }; - }); - }} - /> - - {value.variableType === 'ref' ? ( - { - setValue((s) => { - return { - ...s, - variableValue: v, - }; - }); - }} - placeholder="Please select" - /> - ) : ( - { - setValue((s) => { - return { - ...s, - variableValue: v.target.value, - }; - }); - }} - /> - )} - - ); -}; - -/** - * 支持引用的表单 - * @returns - */ -export const RefForm = (props: { - flowNodes?: NodeDataType[]; - values?: ParameterValue[]; - onChange?: (values: ParameterValue[]) => void; -}) => { - const { flowNodes = [] } = props; - - const { token } = theme.useToken(); - - const panelStyle: React.CSSProperties = { - marginBottom: 24, - background: token.colorFillAlter, - borderRadius: token.borderRadiusLG, - border: 'none', - }; - - const [values, setValues] = useState([ - { - variableName: '', - variableType: 'ref', - variableValue: '', - }, - ]); - - useEffect(() => { - if (props.values) { - setValues(props.values); - } - }, [props.values]); - - useEffect(() => { - props.onChange?.(values); - }, [values]); - - const renderParamters = useMemo(() => { - return values.map((v, i) => { - return ( - { - setValues((s) => { - return [...s.slice(0, i), val, ...s.slice(i + 1)]; - }); - }} - > - ); - }); - }, [values]); - - return ( -
- } - style={{ background: token.colorBgContainer }} - items={[ - { - style: panelStyle, - key: '1', - label: '输入', - children: ( - - -
- 参数名 -
-
- 参考值 -
-
- {renderParamters} -
- -
-
- ), - }, - ]} - >
-
- ); -}; diff --git a/web-packages/magent-flow/src/SchemaConfigForm/index.md b/web-packages/magent-flow/src/SchemaConfigForm/index.md deleted file mode 100644 index 4e6e369..0000000 --- a/web-packages/magent-flow/src/SchemaConfigForm/index.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: SchemaConfigForm -group: { title: 'Schema', order: 1 } -toc: menu -order: 1 -demo: { cols: 2 } ---- - -## 基础用法 - -用于渲染jsonschema config的表单,传入一个FormSchema - -```jsx -import React from 'react'; -import { SchemaConfigForm, FormSchema } from '@alipay/ai-workflow'; - -const mockSchema = new FormSchema(); -mockSchema.updateSchema({ - $schema: 'http://json-schema.org/draft-04/schema#', - type: 'object', - properties: {}, -}); - -export default () => ( - Hi, bigfish -); -``` - - diff --git a/web-packages/magent-flow/src/SchemaConfigForm/index.tsx b/web-packages/magent-flow/src/SchemaConfigForm/index.tsx deleted file mode 100644 index 6b975cf..0000000 --- a/web-packages/magent-flow/src/SchemaConfigForm/index.tsx +++ /dev/null @@ -1,367 +0,0 @@ -/** - * 动态渲染Schema,输出表单卡片 - */ - -import { - AppstoreAddOutlined, - CaretRightOutlined, - MinusCircleOutlined, -} from '@ant-design/icons'; -import { variableTypeOptions } from '@flow/FormSchema/index.js'; -import type { FormSchema, OrderJSONSchema7 } from '@flow/FormSchema/index.js'; -import { Card, Checkbox, Collapse, Form, Input, Select, Space, theme } from 'antd'; -import type { JSONSchema7 } from 'json-schema'; -import React, { useState } from 'react'; - -// import { -// FormSchema, -// OrderJSONSchema7, -// variableTypeOptions, -// } from '../spec/FormSchema'; - -const useForceUpdate = () => { - const [forceKey, update] = useState(0); - const forceUpdate = () => { - update((v) => v + 1); - }; - return { forceUpdate, forceKey }; -}; - -export const SchemaConfigForm = (props: { - formSchema: FormSchema; - showRequired?: boolean; -}) => { - const { formSchema, showRequired = false } = props; - - const jsonschema = formSchema.jsonschema; - const { forceUpdate } = useForceUpdate(); - - const { token } = theme.useToken(); - - const panelStyle: React.CSSProperties = { - marginBottom: 24, - background: token.colorFillAlter, - borderRadius: token.borderRadiusLG, - border: 'none', - }; - - const renderField = ( - schema: JSONSchema7, - pointer: string, - required?: string[], - parentIsArray?: boolean, - isFirstlevel?: boolean, - ) => { - const defaultCase = () => { - const pointers = pointer.split('/'); - const plen = pointer.split('/').length; - const variableName = pointers[plen - 1]; - - const parentPointer = pointer.substring(0, pointer.lastIndexOf('/')); - - let tmpVariableName = variableName; - - const variableType = schema.type as string; - - return ( - - - { - const targetVal = v.target.value; - // 更新key - const success = formSchema.updateField({ - pointer: parentPointer, - key: 'variableName', - value: targetVal, - currentVariableName: tmpVariableName, - }); - if (success) { - tmpVariableName = targetVal; - } - }} - onBlur={forceUpdate} - /> - - - - - - { - formSchema.updateField({ - pointer: parentPointer, - key: 'description', - value: v.target.value, - currentVariableName: variableName, - }); - }} - /> - - {showRequired && ( - - { - formSchema.updateField({ - pointer: parentPointer, - key: 'required', - value: v.target.checked, - currentVariableName: variableName, - }); - }} - > - - )} - {/* {}} /> */} - - ); - }; - switch (schema?.type) { - case 'object': { - const propertiesKeys = Object.keys(schema.properties || {}); - propertiesKeys.sort((a, b) => { - const p = schema.properties as { [key: string]: OrderJSONSchema7 }; - return (p[a]?.order || 999) - (p[b]?.order || 999); - }); - - return ( -
- {!parentIsArray && !isFirstlevel && defaultCase()} - ( - - )} - items={[ - { - style: panelStyle, - key: '1', - label: isFirstlevel ? '输入' : pointer, - extra: ( - { - e.stopPropagation(); - - formSchema.addField({ - pointer: pointer, // 指定属性路径,如 /a/b - type: 'string', - description: '请描述变量的用途', - required: false, - }); - forceUpdate(); - }} - /> - ), - children: propertiesKeys.map((v) => { - const subItemPointer = - pointer === '/' ? pointer + v : pointer + '/' + v; - - return ( -
- {renderField( - schema.properties?.[v] as JSONSchema7, - subItemPointer, - schema.required, - )} -
- ); - }), - }, - ]} - style={{ background: token.colorBgContainer }} - >
-
- ); - } - - case 'array': { - const items = ( - Array.isArray(schema.items) ? schema.items[0] : schema.items - ) as JSONSchema7; - - const itemIsObject = items.type === 'object'; - - const pointers = pointer.split('/'); - const plen = pointer.split('/').length; - const variableName = pointers[plen - 1]; - - const parentPointer = pointer.substring(0, pointer.lastIndexOf('/')); - - let tmpVariableName = variableName; - - let variableType = schema.type as string; - - if (schema.type === 'array') { - const items = ( - Array.isArray(schema.items) ? schema.items[0] : schema.items - ) as JSONSchema7; - if (items) { - variableType = `Array<${items?.type}>`; - } - } - - return ( -
- - - { - const targetVal = v.target.value; - // 更新key - const success = formSchema.updateField({ - pointer: parentPointer, - key: 'variableName', - value: targetVal, - currentVariableName: tmpVariableName, - }); - if (success) { - tmpVariableName = targetVal; - } - }} - onBlur={forceUpdate} - /> - - - - - - { - formSchema.updateField({ - pointer: parentPointer, - key: 'description', - value: v.target.value, - currentVariableName: variableName, - }); - }} - /> - - - { - formSchema.updateField({ - pointer: parentPointer, - key: 'required', - value: v.target.checked, - currentVariableName: variableName, - }); - }} - > - - {}} /> - - {/* 对象才渲染子类型 */} - {itemIsObject && renderField(items, pointer + '/0', schema.required, true)} -
- ); - } - - default: { - return defaultCase(); - } - } - }; - - return ( - - - {renderField(jsonschema, '/', jsonschema.required, false, true)} - - -
{formSchema.log()}
-
-
- ); -}; diff --git a/web-packages/magent-flow/src/components/Flow/index.tsx b/web-packages/magent-flow/src/components/Flow/index.tsx index e664608..986a516 100644 --- a/web-packages/magent-flow/src/components/Flow/index.tsx +++ b/web-packages/magent-flow/src/components/Flow/index.tsx @@ -1,13 +1,12 @@ -import type { Connection, OnSelectionChangeParams } from '@xyflow/react'; -import { Background, ReactFlow } from '@xyflow/react'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; - import type { NodeType } from '@flow/interfaces/flow.js'; import { useFlowStore } from '@flow/stores/useFlowStore.js'; import { useShortcutsStore } from '@flow/stores/useShortcutsStore.js'; import { useUndoRedoStore } from '@flow/stores/useUndoRedoStore.js'; import { getNodeId } from '@flow/utils/reactflowUtils.js'; +import { Background, ReactFlow } from '@xyflow/react'; +import type { Connection, OnSelectionChangeParams } from '@xyflow/react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; import CustomEdge from '../CustomEdge/index.js'; import { FlowController } from '../FlowController/index.js'; @@ -22,6 +21,7 @@ import { handleUndo, } from './keys.js'; import '@xyflow/react/dist/style.css'; +import { EventEmitterContextProvider } from '@flow/context/event-emitter.js'; const edgeTypes = { custom: CustomEdge, @@ -139,33 +139,36 @@ function Flow(props: FlowProps) { } }, []); + console.log('🚀 ~ Flow ~ edges:', edges); return ( -
- +
- - {miniMap && } - {toolbar} - -
+ + + {miniMap && } + {toolbar} + +
+ ); } diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx index 0f5159c..bdf3f78 100644 --- a/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx +++ b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx @@ -30,7 +30,7 @@ const iconMap = { ifelse: ifelseIcon, }; -const yamlContent = ` +const templateNodeYaml = ` - id: 1 name: 开始节点 description: 工作流的起始节点,用于设定启动工作流需要的信息 @@ -225,36 +225,18 @@ const nodeTypes = { export const FlowWithPanel = (props: { toolbar?: React.ReactNode }) => { const { toolbar } = props; - const yaml_data = yaml.load(yamlContent); - (yaml_data as Record[]).forEach((item) => { + const templateNodes = yaml.load(templateNodeYaml); + (templateNodes as Record[]).forEach((item) => { NodeSchemaParser(item); }); - // const setNodes = useFlowStore((state) => state.setNodes); - // const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance); - - // useEffect(() => { - // const add = (yaml_data as any).map((node: any) => { - // return { - // id: node.id, - // type: node.type, - // position: node.position, - // data: node, - // }; - // }); - - // setNodes(add); - // }, [reactFlowInstance]); - return ( - -
- - -
-
+
+ + +
); }; diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml b/web-packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml deleted file mode 100644 index c947a3b..0000000 --- a/web-packages/magent-flow/src/components/FlowWithPanel/nodeTemplate.yaml +++ /dev/null @@ -1,171 +0,0 @@ -- id: 1 - name: 开始节点 - description: 工作流的起始节点,用于设定启动工作流需要的信息 - type: start - data: - outputs: - - name: user_input - type: string - description: 用户本轮对话输入内容 -- id: 2 - name: 结束节点 - description: 工作流的最终节点,用于返回工作流运行后的结果信息 - type: end - data: - inputs: - input_param: - - name: response - type: string - value: - type: reference - content: ['llm1', 'output'] # 通过nodeId + paramKey 定位引用变量 - prompt: - name: response - type: string - description: 输出内容 - value: '{{response}}' -- id: 3 - name: 大模型节点 - description: 调用大语言模型,使用变量和提示词生成回复 - type: llm - position: - x: 1 - y: 2 - data: - inputs: - input_param: - - name: input - description: - type: string - value: - type: reference - content: ['start', 'BOT_USER_INPUT'] - - name: background - description: - type: string - value: - type: reference - content: ['someNode', 'variable2'] - llm_param: - - type: string - name: id - value: qwen_llm - - type: string - name: model_name - value: qwen-max - - type: string - name: temperature - value: '0.7' - - type: string - name: prompt - value: | - 你是一位精通信息分析的ai助手。你的目标是使用中文结合查询的背景信息及你所拥有的知识回答用户提出的问题。 - 你需要遵守的规则是: - 1. 必须使用中文结合查询的背景信息结合你所拥有的知识回答用户提出的问题。 - 2. 结构化答案生成,必要时通过空行提升阅读体验。 - 3. 不采用背景信息中的错误信息。 - 4. 要考虑答案和问题的相关性,不做对问题没有帮助的回答。 - 5. 详尽回答问题,重点突出,不过多花哨词藻。 - 6. 不说模糊的推测。 - 7. 尽量多的使用数值类信息。 - - 背景信息是: - {background} - - 开始! - 需要回答的问题是: {input} - outputs: - - type: string - - name: output -- id: 4 - name: 知识库示例 - description: - type: knowledge - position: - x: 1 - y: 2 - data: - inputs: - knowledge_param: - - type: string - name: id - value: demo_knowledge - - type: string - name: top_k - value: '2' - input_param: - - type: string - name: query # 自然语言的知识库query - value: - type: reference - content: ['1', 'output'] # 通过nodeId + paramKey 定位引用变量 - outputs: - - name: output - type: string -- id: 5 - name: 谷歌搜索工具 - description: - type: tool - position: - x: 1 - y: 2 - data: - inputs: - tool_param: - - type: string - name: id - value: google_search - input_param: - - type: string - name: input - value: - type: value - content: 'output' # 通过nodeId + paramKey 定位引用变量 - outputs: - - name: output - type: string -- id: 4 - name: rag智能体 - description: - type: agent - position: - x: 1 - y: 2 - data: - inputs: - agent_param: - - type: string - name: id - value: demo_rag_agent - input_param: - - type: string - name: input - value: - type: reference - content: ['1', 'output'] # 通过nodeId + paramKey 定位引用变量 - outputs: - - name: output - type: string -- id: 7 - name: 条件判断 - description: - type: ifelse - position: - x: 1 - y: 2 - data: - inputs: - branches: # 这一期这做一层,不包括 and or 还有我理解默认逻辑不展示在这块对吧,只在edge体现 - - name: branch-1 - conditions: - - compare: equal/not-equal/blank - left: - type: string - value: - type: reference - content: ['1', 'output'] - right: # blank 没有right - type: string # 只有 if 和 else,branch-1和branch-default - value: - type: reference - content: ['2', 'output'] diff --git a/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx b/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx index efaf492..dcbd38e 100644 --- a/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/IfElseNode/index.tsx @@ -33,8 +33,8 @@ export const IfElseNode = (props: Props) => { <> diff --git a/web-packages/magent-flow/src/components/Node/LLMNode/index.tsx b/web-packages/magent-flow/src/components/Node/LLMNode/index.tsx index a72df93..4af7cf2 100644 --- a/web-packages/magent-flow/src/components/Node/LLMNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/LLMNode/index.tsx @@ -1,7 +1,4 @@ import { BarsOutlined } from '@ant-design/icons'; -import { Button, InputNumber, Popover } from 'antd'; -import { useEffect, useState } from 'react'; - import { CollapseWrapper } from '@flow/components/AIBasic/CollapseWrapper/index.js'; import { OutputVariable } from '@flow/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; import PromptEditor from '@flow/components/AIBasic/PromptEditor/index.js'; @@ -10,6 +7,8 @@ import { ReferenceForm } from '@flow/components/ReferenceForm/index.js'; import type { BasicSchema, NodeDataType } from '@flow/interfaces/flow.js'; import { useFlowStore } from '@flow/stores/useFlowStore.js'; import { useModelStore } from '@flow/stores/useModelStore.js'; +import { Button, InputNumber, Popover } from 'antd'; +import { useEffect, useState } from 'react'; import { NodeWrapper } from '../NodeWrapper/index.js'; @@ -74,7 +73,7 @@ export const LLMNode = (props: Props) => { label="输入变量" dynamic nodes={[...(upstreamNode as any)]} - value={[...(data.config.inputs?.input_param || [])]} + value={[...(data.config?.inputs?.input_param || [])]} onChange={(values) => { setNode(data.id, (old) => ({ ...old, diff --git a/web-packages/magent-flow/src/components/Node/index.tsx b/web-packages/magent-flow/src/components/Node/index.tsx index e69de29..46ecf9a 100644 --- a/web-packages/magent-flow/src/components/Node/index.tsx +++ b/web-packages/magent-flow/src/components/Node/index.tsx @@ -0,0 +1,8 @@ +export { StartNode } from './StartNode/index.js'; +export { EndNode } from './EndNode/index.js'; +export { AgentNode } from './AgentNode/index.js'; +export { LLMNode } from './LLMNode/index.js'; +export { IfElseNode } from './IfElseNode/index.js'; +export { KnowledgeNode } from './KnowledgeNode/index.js'; +export { CommonNode } from './CommonNode/index.js'; +export { NodeWrapper } from './NodeWrapper/index.js'; diff --git a/web-packages/magent-flow/src/components/RefForm/index.md b/web-packages/magent-flow/src/components/RefForm/index.md deleted file mode 100644 index 5be9d1e..0000000 --- a/web-packages/magent-flow/src/components/RefForm/index.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: RefForm -group: { title: 'Schema', order: 2 } -toc: menu -order: 1 -demo: { cols: 2 } ---- - -## 基本用法 - -> 渲染输入参数表单,支持传入节点引用数据 - -```jsx -import React from 'react'; -import { RefForm, FormSchema, StartNode } from '@alipay/ai-workflow'; - -const startNode = new StartNode(); -startNode.input.updateSchema({ - type: 'object', - properties: { - name: { - type: 'string', - title: '姓名', - }, - }, -}); - -export default () => Hi, bigfish; -``` - - diff --git a/web-packages/magent-flow/src/index.ts b/web-packages/magent-flow/src/index.ts index bd969b6..9f1d66b 100644 --- a/web-packages/magent-flow/src/index.ts +++ b/web-packages/magent-flow/src/index.ts @@ -1,13 +1,14 @@ export { default as Flow } from './components/Flow/index.js'; export { FlowWithPanel } from './components/FlowWithPanel/index.js'; -export { FormSchema } from './FormSchema/index.js'; -export { RefForm } from './RefForm/index.js'; -export { SchemaConfigForm } from './SchemaConfigForm/index.js'; +export { NodesPanel } from './components/NodePanel/index.js'; +export type { Edge } from '@xyflow/react'; + export { useFlowStore } from './stores/useFlowStore.js'; export { useModelStore } from './stores/useModelStore.js'; export { useKnowledgeStore } from './stores/useKnowledgeStore.js'; -export { StartNode } from './spec/node.js'; + export * from './utils/index.js'; import './tailwind.out.css'; +export * from './components/Node/index.js'; export * from './interfaces/flow.js'; diff --git a/web-packages/magent-flow/src/interfaces/flow.ts b/web-packages/magent-flow/src/interfaces/flow.ts index d6e99a7..f0777c7 100644 --- a/web-packages/magent-flow/src/interfaces/flow.ts +++ b/web-packages/magent-flow/src/interfaces/flow.ts @@ -77,7 +77,7 @@ export interface NodeDataType { status: string; result?: any; }; - name: string; + name?: string; icon?: string; description?: string; config?: NodeDataConfigType; diff --git a/web-packages/magent-flow/src/spec/FormSchema/index.ts b/web-packages/magent-flow/src/spec/FormSchema/index.ts deleted file mode 100644 index 3bc0582..0000000 --- a/web-packages/magent-flow/src/spec/FormSchema/index.ts +++ /dev/null @@ -1,328 +0,0 @@ -import { message } from 'antd'; -import type { - JSONSchema7, - JSONSchema7Definition, - JSONSchema7TypeName, -} from 'json-schema'; - -import { UUID } from '../uuid.js'; - -export type OrderJSONSchema7 = JSONSchema7 & { - order: number; -}; - -export interface CascaderOptions { - value: string; - label: string; - children?: CascaderOptions[]; -} - -/** - * 声明输入的表单数据格式 - * 表单内容 - */ -export class FormSchema { - uuid = UUID.getInstance().uniqueID(); - - jsonschema: JSONSchema7 = { - $id: this.uuid, - type: 'object', - properties: {}, - required: [], - }; - - /** - * 获取指定路径的属性 - * 方便添加属性 - * /a/b/c/ - * @param pointer - * @returns - */ - getSchemaByPoint(pointer: string) { - if (pointer === '/' || pointer === '') { - return this.jsonschema; - } - - let pointers = pointer.split('/'); - if (pointers[0] !== '') { - throw new Error('invalid pointer'); - } - pointers = pointers.slice(1); - - // base是一个object模式 - let schema = this.jsonschema; - while (pointers.length > 0) { - const pointer = pointers.shift(); - if (pointer === undefined) { - throw new Error('invalid pointer'); - } - if (schema) { - if (schema.type === 'object') { - if (schema?.properties?.[pointer]) { - // 有就递归下沉 - schema = schema.properties[pointer] as JSONSchema7; - } else { - // 没有属性就添加 - schema!.properties![pointer] = {}; - return schema!.properties![pointer]; - } - } else if (schema?.type === 'array') { - if (schema?.items) { - const index = parseInt(pointer); - if (Array.isArray(schema.items)) { - schema = schema.items[index] as JSONSchema7; - } else { - schema = schema.items as JSONSchema7; - } - } - } - } - } - return schema; - } - - private randommName = () => { - return ( - 'RandaomName__-' + - Math.random().toString(36).substring(2, 15) + - Math.random().toString(36).substring(2, 15) - ); - }; - - isRandomName = (name: string) => { - return name.startsWith('RandaomName__-'); - }; - - /** - * 动态表单添加属性 - * @param property - * @returns - */ - addField = (options: { - pointer: string; // 指定属性路径,如 /a/b - name?: string; - type: JSONSchema7TypeName; - description: string; - required: boolean; - }) => { - const { pointer, name = this.randommName(), type, description, required } = options; - if (typeof this.jsonschema !== 'boolean') { - const schema = this.getSchemaByPoint(pointer); - if (schema.type === 'array') { - // 如果存在属性 - if (!schema?.items) { - schema.items = { - type: type, - description, - }; - } else if (!Array.isArray(schema?.items)) { - const items = schema.items as JSONSchema7Definition; - schema.items = [ - items, - { - type: type, - description, - }, - ]; - } else if (Array.isArray(schema?.items)) { - schema.items.push({ - type: type, - description, - }); - } - } else if (schema?.type === 'object') { - // 使用order 记录顺序 - let order = 0; - Object.entries(schema.properties || {}).forEach(([, val]) => { - const v = val as OrderJSONSchema7; - if (v?.order) { - order = v?.order > order ? v?.order : order; - } - }); - - (schema.properties![name] as OrderJSONSchema7) = { - type: type, - description, - order: order + 1, - }; - if (type === 'object') { - schema.properties![name].properties = {}; - } - } else { - schema.type = type; - schema.description = description; - } - if (required) { - // 如果是object的话,require在当前位置添加 - if (schema.type === 'object') { - if (!schema.required) { - schema.required = []; - } - schema.required = [...schema.required, name]; - } else { - // 在父级添加 - const parentPointer = pointer.split('/').slice(0, -1).join('/'); - const parentSchema = this.getSchemaByPoint(parentPointer); - - if (!parentSchema.required) { - parentSchema.required = []; - } - parentSchema.required = [...parentSchema.required, name]; - } - } - } - return false; - }; - - /** - * 动态表单更新属性 - * @param property - * @returns - */ - updateField = (options: { - pointer: string; // 指定属性路径,如 /a/b - key: 'variableName' | 'variableType' | 'description' | 'required'; - value: any; - currentVariableName: string; - }) => { - const { pointer, key, value, currentVariableName } = options; - if (typeof this.jsonschema !== 'boolean') { - const schema = this.getSchemaByPoint(pointer); - if (schema.type === 'object') { - if (schema.properties) { - if (key === 'variableName') { - const old = schema.properties?.[currentVariableName]; - if (value !== currentVariableName) { - schema.properties[value] = old; - delete schema.properties[currentVariableName]; - } else { - message.info('变量名不能和已有变量名相同'); - return false; - } - return true; - } - if (key === 'variableType') { - if ((schema.properties[currentVariableName] as JSONSchema7).type) { - // 处理数组类型 - if (value.startsWith('Array<')) { - const t = ( - value.replace('Array<', '').replace('>', '') as string - ).toLocaleLowerCase(); - schema.properties[currentVariableName].type = 'array'; - schema.properties[currentVariableName].items = { - type: t, - }; - if (t === 'object') { - schema.properties[currentVariableName].items.properties = {}; - } - return true; - } - if (value === 'object') { - schema.properties[currentVariableName].type = value; - schema.properties[currentVariableName].properties = {}; - return true; - } - - // 基础类型 - schema.properties[currentVariableName].type = value; - delete schema.properties[currentVariableName].items; - delete schema.properties[currentVariableName].properties; - - return true; - } - } - if (key === 'description') { - if (schema.properties[currentVariableName] as JSONSchema7) { - schema.properties[currentVariableName].description = value; - return true; - } - } - if (key === 'required') { - if (!this.isRandomName(currentVariableName)) { - if (schema.properties[currentVariableName]) { - if (!schema.required) { - schema.required = []; - } - if (value) { - if (!schema.required?.includes(value)) { - schema.required?.push(currentVariableName); - } - } else { - if (schema.required?.includes(currentVariableName)) { - schema.required = schema.required.filter( - (item) => item !== currentVariableName, - ); - } - } - - return true; - } - } - } - } - } - } - return false; - }; - - updateSchema(schema: JSONSchema7) { - Object.assign(this.jsonschema, schema); - } - - log() { - return JSON.stringify(this.jsonschema, null, 4); - } -} - -export const variableTypeOptions: { - label: string; - value: - | JSONSchema7TypeName - | 'Array' - | 'Array' - | 'Array' - | 'Array' - | 'Array'; -}[] = [ - { - label: 'String', - value: 'string', - }, - { - label: 'Integer', - value: 'integer', - }, - { - label: 'Boolean', - value: 'boolean', - }, - { - label: 'Number', - value: 'number', - }, - { - label: 'Object', - value: 'object', - }, - - { - label: 'Array', - value: 'Array', - }, - { - label: 'Array', - value: 'Array', - }, - { - label: 'Array', - value: 'Array', - }, - { - label: 'Array', - value: 'Array', - }, - { - label: 'Array', - value: 'Array', - }, -]; diff --git a/web-packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap b/web-packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap deleted file mode 100644 index 6729cd7..0000000 --- a/web-packages/magent-flow/src/spec/__snapshots__/node.test.ts.snap +++ /dev/null @@ -1,65 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`addField 添加表单field 1`] = ` -"{ - "$id": "5", - "type": "object", - "properties": { - "a": { - "type": "object", - "description": "this is a", - "order": 1, - "properties": {} - } - }, - "required": [] -}" -`; - -exports[`addField 添加表单field1 1`] = ` -"{ - "$id": "6", - "type": "object", - "properties": { - "a": { - "type": "object", - "description": "this is a", - "order": 1, - "properties": { - "b": { - "type": "string", - "description": "this is desc" - }, - "subA": { - "type": "object", - "description": "this is desc", - "order": 1, - "properties": { - "aryC": { - "type": "array", - "description": "this is desc", - "order": 1 - } - }, - "required": [ - "aryC" - ] - } - }, - "required": [ - "b", - "subA" - ] - }, - "first": { - "type": "object", - "description": "this is a", - "order": 2, - "properties": {} - } - }, - "required": [ - "first" - ] -}" -`; diff --git a/web-packages/magent-flow/src/spec/node.test.ts b/web-packages/magent-flow/src/spec/node.test.ts deleted file mode 100644 index 7cb78f7..0000000 --- a/web-packages/magent-flow/src/spec/node.test.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { FormSchema } from './FormSchema'; - -describe('getSchemaByPoint', () => { - it('基础路径 /', () => { - const input = new FormSchema(); - input.jsonschema = { - type: 'object', - properties: { - a: { - type: 'string', - description: 'this is a', - }, - b: { - type: 'object', - properties: { - c: { - type: 'array', - items: { - type: 'string', - }, - }, - }, - }, - }, - }; - - expect(input.getSchemaByPoint('/')).toEqual({ - type: 'object', - properties: { - a: { - type: 'string', - description: 'this is a', - }, - b: { - type: 'object', - properties: { - c: { - type: 'array', - items: { - type: 'string', - }, - }, - }, - }, - }, - }); - }); - - it('如果对应路径没有参数,应该创建一个properties对象,并且返回该对象', () => { - const input = new FormSchema(); - input.jsonschema = { - type: 'object', - properties: {}, - }; - - const got = input.getSchemaByPoint('/a'); - // 没有对应的属性 - expect(got).toEqual({}); - - expect(input.jsonschema).toEqual({ - type: 'object', - properties: { - a: {}, - }, - }); - }); - - it('获取对应的schema', () => { - const input = new FormSchema(); - input.jsonschema = { - type: 'object', - properties: { - a: { - type: 'string', - description: 'this is a', - }, - b: { - type: 'object', - properties: { - c: { - type: 'array', - items: { - type: 'string', - }, - }, - }, - }, - }, - }; - expect(input.getSchemaByPoint('/a')).toEqual({ - type: 'string', - description: 'this is a', - }); - - expect(input.getSchemaByPoint('/b')).toEqual({ - type: 'object', - properties: { - c: { - type: 'array', - items: { - type: 'string', - }, - }, - }, - }); - }); - - it('数组则返回对应的数组对象', () => { - const input = new FormSchema(); - input.jsonschema = { - type: 'object', - properties: { - a: { - type: 'string', - description: 'this is a', - }, - b: { - type: 'object', - properties: { - c: { - type: 'array', - items: { - type: 'string', - }, - }, - }, - }, - }, - }; - - // 数组则返回对应的对象 - expect(input.getSchemaByPoint('/b/c')).toEqual({ - type: 'array', - items: { - type: 'string', - }, - }); - }); -}); - -describe('addField', () => { - it('添加表单field', () => { - const input = new FormSchema(); - input.addField({ - pointer: '/', // 指定属性路径,如 /a/b - name: 'a', - type: 'object', - description: 'this is a', - required: false, - }); - const got = input.log(); - expect(got).toMatchSnapshot(); - // expect(1).toBe(0); - }); - - it('添加表单field1', () => { - const input = new FormSchema(); - input.addField({ - pointer: '/', // 指定属性路径,如 /a/b - name: 'a', - type: 'object', - description: 'this is a', - required: false, - }); - input.addField({ - pointer: '/a/b', // 指定属性路径,如 /a/b - name: 'b', - type: 'string', - description: 'this is desc', - required: true, - }); - input.addField({ - pointer: '/a', // 指定属性路径,如 /a/b - name: 'subA', - type: 'object', - description: 'this is desc', - required: true, - }); - input.addField({ - pointer: '/a/subA', // 指定属性路径,如 /a/b - name: 'aryC', - type: 'array', - description: 'this is desc', - required: true, - }); - input.addField({ - pointer: '/', // 指定属性路径,如 /a/b - name: 'first', - type: 'object', - description: 'this is a', - required: true, - }); - const got = input.log(); - expect(got).toMatchSnapshot(); - }); -}); diff --git a/web-packages/magent-flow/src/spec/node.ts b/web-packages/magent-flow/src/spec/node.ts deleted file mode 100644 index f415454..0000000 --- a/web-packages/magent-flow/src/spec/node.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { - NodeDataConfigType, - NodeDataMetaType, - NodeDataType, -} from '@flow/interfaces/flow.js'; -import { NodeTypeEnum } from '@flow/interfaces/flow.js'; - -import { FormSchema } from './FormSchema/index.js'; -import { UUID } from './uuid.js'; - -// 不同类型的节点的基础类 -// - -/** - * 开始节点 - * 只设置输入 - * 输出和输入一致 - */ -export class StartNode implements NodeDataType { - id: string = UUID.getInstance().uniqueID(); - - type: NodeTypeEnum = NodeTypeEnum.Start; - - config: NodeDataConfigType | undefined = { - params: undefined, - inputs: new FormSchema(), - outputs: new FormSchema(), - }; - - nodeMeta: NodeDataMetaType = { - title: '开始节点', - description: '开始节点', - }; - - toJson() { - const node: NodeDataType = { - id: this.id, - nodeType: this.nodeType, - nodeMeta: this.nodeMeta, - config: this.config, - }; - return JSON.stringify(node); - } - - fromJson(json: string) { - try { - const node: NodeDataType = JSON.parse(json); - - this.id = node.id; - this.nodeType = node.nodeType; - this.nodeMeta = node.nodeMeta; - this.config = node.config; - } catch (error) {} - } - - toXYFlowJson() {} -} - -// /** -// * 插件节点 -// */ -// export class PluginNode implements FlowNode { -// extend(e) {} -// } -// class BingPluginNode extends PluginNode {} - -// new BingPluginNode().extend({ -// inpot: (JSONSchema = { -// type: 'object', -// properties: { -// count: { -// type: 'integer', -// }, -// offset: { -// type: 'integer', -// }, -// query: { -// type: 'string', -// }, -// }, -// required: ['a'], -// }), -// }); diff --git a/web-packages/magent-flow/src/spec/test-jsonschema.json b/web-packages/magent-flow/src/spec/test-jsonschema.json deleted file mode 100644 index 6a3b36f..0000000 --- a/web-packages/magent-flow/src/spec/test-jsonschema.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "properties": { - "a": { - "type": "integer" - }, - "b": { - "type": "string" - }, - "c": { - "type": "boolean" - }, - "e": { - "type": "object", - "properties": { - "f": { - "type": "integer" - }, - "g": { - "type": "string" - }, - "h": { - "type": "boolean" - }, - "j": { - "type": "object", - "properties": { - "k": { - "type": "integer" - }, - "l": { - "type": "string" - }, - "m": { - "type": "boolean" - } - }, - "required": ["k", "l", "m", "n"] - } - }, - "required": ["f", "g", "h", "i", "j"] - }, - "f": { - "type": "array", - "items": [ - { - "type": "integer" - } - ] - }, - "g": { - "type": "array", - "items": [ - { - "type": "string" - } - ] - }, - "h": { - "type": "array", - "items": [ - { - "type": "object", - "properties": { - "i": { - "type": "integer" - }, - "j": { - "type": "string" - }, - "k": { - "type": "array", - "items": [ - { - "type": "string" - } - ] - } - }, - "required": ["i", "j", "k"] - } - ] - } - }, - "required": ["a", "b", "c", "d", "e", "f", "g", "h"] -} diff --git a/web-packages/magent-flow/src/spec/uuid.ts b/web-packages/magent-flow/src/spec/uuid.ts deleted file mode 100644 index 107c8f1..0000000 --- a/web-packages/magent-flow/src/spec/uuid.ts +++ /dev/null @@ -1,21 +0,0 @@ -export class UUID { - private static instance: UUID; - - static getInstance() { - if (!UUID.instance) { - UUID.instance = new UUID(); - } - return UUID.instance; - } - - private _id = 0; - - /** - * 返回一个数字id - * @returns - */ - uniqueID() { - this._id += 1; - return this._id.toString(); - } -} diff --git a/web-packages/magent-flow/src/stores/useFlowStore.ts b/web-packages/magent-flow/src/stores/useFlowStore.ts index dcb7004..dd06f54 100644 --- a/web-packages/magent-flow/src/stores/useFlowStore.ts +++ b/web-packages/magent-flow/src/stores/useFlowStore.ts @@ -1,3 +1,5 @@ +import type { NodeType } from '@flow/interfaces/flow.js'; +import { cleanEdges, getNodeId } from '@flow/utils/reactflowUtils.js'; import type { Connection, Edge, @@ -14,9 +16,6 @@ import { addEdge, applyEdgeChanges, applyNodeChanges } from '@xyflow/react'; import { cloneDeep } from 'lodash'; import { create } from 'zustand'; -import type { NodeType } from '@flow/interfaces/flow.js'; -import { cleanEdges, getNodeId } from '@flow/utils/reactflowUtils.js'; - interface AdjacencyList { [key: number]: number[]; } @@ -24,6 +23,10 @@ interface AdjacencyList { interface FlowStoreType { nodes: Node[]; edges: Edge[]; + initFlow: (grapg: { nodes: Node[]; edges: Edge[] }) => { + nodes: Node[]; + edges: Edge[]; + }; onNodesChange: OnNodesChange; onEdgesChange: OnEdgesChange; @@ -89,6 +92,12 @@ export const useFlowStore = create((set, get) => { return { nodes: [], edges: [], + initFlow: (graph: { nodes: Node[]; edges: Edge[] }) => { + set({ + nodes: graph.nodes, + edges: graph.edges, + }); + }, reactFlowInstance: null, setReactFlowInstance: (newState) => { set({ reactFlowInstance: newState }); @@ -114,6 +123,7 @@ export const useFlowStore = create((set, get) => { edges: applyEdgeChanges(changes, get().edges), }); }, + setNode: (id: string, change: Node | ((oldState: Node) => Node)) => { const newChange = typeof change === 'function' @@ -185,9 +195,7 @@ export const useFlowStore = create((set, get) => { targetHandle: connection.targetHandle!, sourceHandle: connection.sourceHandle!, }, - // style: { stroke: "#555" }, type: 'custom', - // className: "stroke-foreground stroke-connection", }, oldEdges, ); From 7db1a5fd2f01c47c7ef4be6c2926c32001da2aac Mon Sep 17 00:00:00 2001 From: OctoberRain <572626298@qq.com> Date: Thu, 29 Aug 2024 21:14:56 +0800 Subject: [PATCH 26/78] feat: magent-ui support knowledge curd operation --- .../src/magent_ui/routers/knowledge/router.py | 23 ++- web-apps/ui/config/routes.ts | 4 + .../modules/knowledge/knowledge-manager.ts | 21 +++ .../src/views/knowledge/create-modal/index.ts | 10 ++ .../views/knowledge/create-modal/modal.tsx | 143 ++++++++++++++++++ web-apps/ui/src/views/knowledge/index.less | 43 ++++++ web-apps/ui/src/views/knowledge/module.ts | 9 ++ web-apps/ui/src/views/knowledge/protocol.ts | 1 + .../ui/src/views/knowledge/upload-view.tsx | 72 +++++++++ web-apps/ui/src/views/knowledge/view.tsx | 66 ++++++-- 10 files changed, 378 insertions(+), 14 deletions(-) create mode 100644 web-apps/ui/src/views/knowledge/create-modal/index.ts create mode 100644 web-apps/ui/src/views/knowledge/create-modal/modal.tsx create mode 100644 web-apps/ui/src/views/knowledge/protocol.ts create mode 100644 web-apps/ui/src/views/knowledge/upload-view.tsx diff --git a/packages/magent-ui/src/magent_ui/routers/knowledge/router.py b/packages/magent-ui/src/magent_ui/routers/knowledge/router.py index 7fdedbf..c46c70f 100644 --- a/packages/magent-ui/src/magent_ui/routers/knowledge/router.py +++ b/packages/magent-ui/src/magent_ui/routers/knowledge/router.py @@ -1,5 +1,5 @@ -from typing import List -from fastapi import APIRouter +from typing import Annotated, List +from fastapi import APIRouter, Body, File, UploadFile from agentuniverse_product.service.model.knowledge_dto import KnowledgeDTO from agentuniverse_product.service.knowledge_service.knowledge_service import KnowledgeService @@ -10,3 +10,22 @@ @router.get("/knowledge", response_model=List[KnowledgeDTO]) async def get_knowledge(): return KnowledgeService.get_knowledge_list() + +@router.post("/knowledge", response_model=str) +async def create_knowledge(knowledge: KnowledgeDTO): + return KnowledgeService.create_knowledge(knowledge) + +@router.put("/knowledge/{knowledge_id}", response_model=str) +async def update_knowledge(knowledge_id: str, knowledge: KnowledgeDTO): + knowledge.id = knowledge_id + return KnowledgeService.update_knowledge(knowledge) + +@router.delete("/knowledge/{knowledge_id}", response_model=bool) +async def delete_knowledge(knowledge_id: str): + return KnowledgeService.delete_knowledge(knowledge_id) + +@router.post("/knowledge/upload") +async def upload_knowledge_file(knowledge_id: Annotated[str, Body()], file: UploadFile = File(...)): + print('here') + return KnowledgeService.upload_knowledge_file(knowledge_id, file) + \ No newline at end of file diff --git a/web-apps/ui/config/routes.ts b/web-apps/ui/config/routes.ts index e28e0db..4357809 100644 --- a/web-apps/ui/config/routes.ts +++ b/web-apps/ui/config/routes.ts @@ -34,6 +34,10 @@ export default [ path: '/agent/:agentId/flow', slot: 'magent-agent-flow-dev-slot', }, + { + path: '/portal/knowledge/:knowledgeId/upload', + slot: 'magent-knowledge-upload-slot', + }, ], }, ]; diff --git a/web-apps/ui/src/modules/knowledge/knowledge-manager.ts b/web-apps/ui/src/modules/knowledge/knowledge-manager.ts index 57b6490..83b5986 100644 --- a/web-apps/ui/src/modules/knowledge/knowledge-manager.ts +++ b/web-apps/ui/src/modules/knowledge/knowledge-manager.ts @@ -26,6 +26,27 @@ export class KnowledgeManager { return defaultValue; }; + createKnowledge = async (nickname: string, description?: string): Promise => { + const res = await this.axios.post(`/api/v1/knowledge`, { + nickname: nickname, + description: description, + }); + return res.data; + }; + + updateKnowledge = async (option: KnowledgeModelOption): Promise => { + const res = await this.axios.put(`/api/v1/knowledge/${option.id}`, { + nickname: option.nickname, + description: option.description, + }); + return res.data; + }; + + deleteKnowledge = async (knowledge_id: string): Promise => { + const res = await this.axios.delete(`/api/v1/knowledge/${knowledge_id}`); + return Boolean(res.data); + }; + getOrCreate = (option: KnowledgeModelOption): KnowledgeModel => { const exist = this.cache.get(option.id); if (exist) { diff --git a/web-apps/ui/src/views/knowledge/create-modal/index.ts b/web-apps/ui/src/views/knowledge/create-modal/index.ts new file mode 100644 index 0000000..3de3bd4 --- /dev/null +++ b/web-apps/ui/src/views/knowledge/create-modal/index.ts @@ -0,0 +1,10 @@ +import { ModalContribution, singleton } from '@difizen/mana-app'; + +import { KnowledgeModal } from './modal.js'; + +@singleton({ contrib: [ModalContribution] }) +export class KnowledgeModalContribution implements ModalContribution { + registerModal() { + return KnowledgeModal; + } +} diff --git a/web-apps/ui/src/views/knowledge/create-modal/modal.tsx b/web-apps/ui/src/views/knowledge/create-modal/modal.tsx new file mode 100644 index 0000000..d89ee78 --- /dev/null +++ b/web-apps/ui/src/views/knowledge/create-modal/modal.tsx @@ -0,0 +1,143 @@ +import type { ModalItem, ModalItemProps } from '@difizen/mana-app'; +import { useInject, useMount } from '@difizen/mana-app'; +import { Form, Input, message, Modal } from 'antd'; +import React, { useCallback, useMemo, useState } from 'react'; +import { history } from 'umi'; + +import { KnowledgeManager } from '../../../modules/knowledge/knowledge-manager.js'; +import { KnowledgeSpace } from '../../../modules/knowledge/knowledge-space.js'; +import { KnowledgeModalId } from '../protocol.js'; +import { KnowledgeView } from '../view.js'; + +export const KnowledgeModalComponent = ( + props: ModalItemProps<{ type: 'create' | 'edit'; knowledge_id?: string }>, +) => { + const knowledgeSpace = useInject(KnowledgeSpace); + const knowledgeManager = useInject(KnowledgeManager); + const instance = useInject(KnowledgeView); + + const { visible, close, data } = props; + + const [form] = Form.useForm(); + + const [nameValue, setName] = useState(undefined); + const [idValue, setId] = useState(undefined); + + useMount(() => { + knowledgeSpace.update(); + }); + + const strategiesValues = useMemo( + () => ({ + create: { + title: '创建知识库', + okText: '创建', + }, + edit: { + title: '编辑知识库', + okText: '确定', + }, + }), + [], + ); + + const strategiesMethod = useMemo( + () => ({ + create: async () => { + const formValues = form.getFieldsValue(); + const id = await knowledgeManager.createKnowledge( + formValues.nickname, + formValues.description, + ); + if (id) { + setId(id); + message.success('创建成功'); + history.push(`/portal/knowledge/${id}/upload`); + } + close(); + }, + edit: async () => { + if (!data?.knowledge_id) { + return; + } + const formValues = form.getFieldsValue(); + const id = await knowledgeManager.updateKnowledge({ + id: data.knowledge_id, + nickname: formValues.nickname, + description: formValues.description, + }); + if (id) { + setId(id); + message.success('更新成功'); + await instance.update(); + } + close(); + }, + }), + [close, data, form, instance, knowledgeManager], + ); + + const submit = useCallback(async () => { + const method = strategiesMethod[data?.type || 'create']; + if (method) { + await method(); + } else { + console.error('Invalid type'); + } + }, [data, strategiesMethod]); + + return ( + close()} + cancelText="取消" + onOk={() => submit()} + okText={strategiesValues[data?.type || 'create'].okText} + > +
{ + const idChanged = changed.find( + (item) => + item.name instanceof Array && + item.name.length === 1 && + item.name[0] === 'nickname', + ); + if (idChanged && idChanged.validated) { + setName(idChanged.value); + } + }} + > + + + + {/* + { + const extname = path.extname(file.name); + const filename = `${nameValue}${extname}`; + return { + file, + filename, + }; + }} + AvatarRender={UploadButton} + /> + */} + + + +
+
+ ); +}; + +export const KnowledgeModal: ModalItem = { + id: KnowledgeModalId, + component: KnowledgeModalComponent, +}; diff --git a/web-apps/ui/src/views/knowledge/index.less b/web-apps/ui/src/views/knowledge/index.less index c12771d..d94915e 100644 --- a/web-apps/ui/src/views/knowledge/index.less +++ b/web-apps/ui/src/views/knowledge/index.less @@ -32,6 +32,11 @@ &-col { display: flex; align-items: center; + + a { + text-decoration: none; + color: #1677ff; + } } } @@ -50,6 +55,19 @@ height: 100%; } + &-creation { + position: absolute; + top: -64px; + right: 24px; + height: 64px; + display: flex; + align-items: center; + + button { + border: none; + } + } + .ant-list-items { padding-bottom: 24px; overflow-y: auto; @@ -68,3 +86,28 @@ width: 100%; } } + +.magent-knowledge-upload { + &-wrapper { + display: flex; + justify-content: center; + } + + &-dragger { + display: block; + width: 800px; + margin: 128px 0; + background-color: rgba(247, 247, 250); + + .ant-upload-drag { + border-width: 3px; + height: 200px; + } + } + + &-dragger:hover { + .ant-upload-drag { + background-color: #4096ff15; + } + } +} diff --git a/web-apps/ui/src/views/knowledge/module.ts b/web-apps/ui/src/views/knowledge/module.ts index b21e340..c6a31a2 100644 --- a/web-apps/ui/src/views/knowledge/module.ts +++ b/web-apps/ui/src/views/knowledge/module.ts @@ -2,6 +2,8 @@ import { createViewPreference, ManaModule } from '@difizen/mana-app'; import { KnowledgeModule } from '@/modules/knowledge/module.js'; +import { KnowledgeModalContribution } from './create-modal/index.js'; +import { KnowledgeUploadView, uploadslot } from './upload-view.js'; import { KnowledgeView, slot } from './view.js'; export const KnowledgePageModule = ManaModule.create() @@ -12,5 +14,12 @@ export const KnowledgePageModule = ManaModule.create() view: KnowledgeView, autoCreate: true, }), + KnowledgeModalContribution, + KnowledgeUploadView, + createViewPreference({ + slot: uploadslot, + view: KnowledgeUploadView, + autoCreate: true, + }), ) .dependOn(KnowledgeModule); diff --git a/web-apps/ui/src/views/knowledge/protocol.ts b/web-apps/ui/src/views/knowledge/protocol.ts new file mode 100644 index 0000000..e94e632 --- /dev/null +++ b/web-apps/ui/src/views/knowledge/protocol.ts @@ -0,0 +1 @@ +export const KnowledgeModalId = 'knowledge.modal'; diff --git a/web-apps/ui/src/views/knowledge/upload-view.tsx b/web-apps/ui/src/views/knowledge/upload-view.tsx new file mode 100644 index 0000000..9cd7a0f --- /dev/null +++ b/web-apps/ui/src/views/knowledge/upload-view.tsx @@ -0,0 +1,72 @@ +import { InboxOutlined } from '@ant-design/icons'; +import { BaseView, inject, prop, singleton, view } from '@difizen/mana-app'; +import { message, Upload } from 'antd'; + +import './index.less'; +import { history } from 'umi'; +import { useParams } from 'umi'; + +import { MainView } from '@/modules/base-layout/main-view.js'; +import type { NavigatablePage } from '@/modules/base-layout/protocol.js'; + +const { Dragger } = Upload; + +const viewId = 'magent-knowledge-upload'; +export const uploadslot = `${viewId}-slot`; + +const KnowledgeUploadComponent = () => { + const { knowledgeId } = useParams(); + + return ( +
+ { + const { status } = info.file; + if (status === 'done') { + message.success(`${info.file.name} file uploaded successfully.`); + } else if (status === 'error') { + message.error(`${info.file.name} file upload failed.`); + } + }} + // onDrop={(e) => {}} + > +

+ +

+

Click or drag file to this area to upload

+

+ Support for a single or bulk upload. Strictly prohibited from uploading + company data or other banned files. +

+
+
+ ); +}; + +@singleton() +@view(viewId) +export class KnowledgeUploadView extends BaseView implements NavigatablePage { + @inject(MainView) protected mainView: MainView; + + override view = KnowledgeUploadComponent; + + override onViewUnmount(): void { + this.mainView.active = undefined; + } + override onViewMount(): void { + this.mainView.active = this; + } + + goBack = () => history.push('/portal/knowledge'); + + pageTitle = () => <>上传知识; +} diff --git a/web-apps/ui/src/views/knowledge/view.tsx b/web-apps/ui/src/views/knowledge/view.tsx index 6eb4586..a1010f3 100644 --- a/web-apps/ui/src/views/knowledge/view.tsx +++ b/web-apps/ui/src/views/knowledge/view.tsx @@ -1,6 +1,7 @@ /* eslint-disable react/prop-types */ import { BaseView, + ModalService, ViewInstance, inject, prop, @@ -8,7 +9,7 @@ import { useInject, view, } from '@difizen/mana-app'; -import { Col, List, Row } from 'antd'; +import { Button, Col, List, message, Row, Space } from 'antd'; import { forwardRef, useState } from 'react'; import { KnowledgeIcon } from '@/modules/knowledge/knowledge-icon.js'; @@ -19,6 +20,8 @@ import type { } from '@/modules/knowledge/protocol.js'; import './index.less'; +import { KnowledgeModal } from './create-modal/modal.js'; +import { history } from 'umi'; const viewId = 'magent-knowledge'; export const slot = `${viewId}-slot`; @@ -28,20 +31,13 @@ const KnowledgeViewComponent = forwardRef( const instance = useInject(ViewInstance); const [selectedItems, setSelectedItems] = useState([]); - const handSelect = (item: KnowledgeModelOption) => { - if (selectedItems.findIndex((selectedItem) => selectedItem.id === item.id) > -1) { - setSelectedItems( - selectedItems.filter((selectedItem) => selectedItem.id !== item.id), - ); - } else { - setSelectedItems([...selectedItems, item]); - } - }; + const modalService = useInject(ModalService); + return (
- 工具 + 知识 简介 @@ -68,11 +64,57 @@ const KnowledgeViewComponent = forwardRef( > {item.description} - + + + + modalService.openModal(KnowledgeModal, { + type: 'edit', + knowledge_id: item.id, + }) + } + > + 编辑 + + + history.push(`/portal/knowledge/${item.id}/upload`) + } + > + 上传 + + { + const res = await instance.manager.deleteKnowledge(item.id); + if (res) { + message.success('删除成功'); + await instance.update(); + } + }} + > + 删除 + + + )} /> + +
+ +
); }, From 8d1d1f5cd81941e48a80e5d5d8f1705d6bb55fb2 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Thu, 29 Aug 2024 21:29:15 +0800 Subject: [PATCH 27/78] feat(ui): add plugin --- .../magent-ui/src/magent_ui/routers/main.py | 4 + .../src/magent_ui/routers/plugins/__init__.py | 0 .../src/magent_ui/routers/plugins/router.py | 16 ++ .../src/common/component/component-model.ts | 54 ++++++ web-apps/ui/src/common/component/protocol.ts | 6 + .../ui/src/components/tag-list/index.less | 12 ++ web-apps/ui/src/components/tag-list/index.tsx | 73 ++++++++ web-apps/ui/src/modules/agent/agent-model.ts | 4 +- web-apps/ui/src/modules/agent/protocol.ts | 6 +- web-apps/ui/src/modules/app.module.ts | 4 + web-apps/ui/src/modules/plugin/icon/index.tsx | 20 ++ .../ui/src/modules/plugin/icon/plugin.svg | 1 + web-apps/ui/src/modules/plugin/module.ts | 26 +++ .../ui/src/modules/plugin/plugin-manager.ts | 52 ++++++ .../ui/src/modules/plugin/plugin-model.ts | 75 ++++++++ web-apps/ui/src/modules/plugin/protocol.ts | 22 +++ web-apps/ui/src/modules/tool/icon/index.tsx | 20 ++ web-apps/ui/src/modules/tool/icon/tool.svg | 1 + web-apps/ui/src/modules/tool/protocol.ts | 6 +- web-apps/ui/src/modules/tool/tool-icon.tsx | 56 ------ web-apps/ui/src/modules/tool/tool-manager.ts | 12 +- web-apps/ui/src/modules/tool/tool-model.ts | 36 ++-- web-apps/ui/src/views/agent-config/index.tsx | 1 - .../views/agent-config/tools-modal/modal.tsx | 11 +- web-apps/ui/src/views/agent-config/view.tsx | 2 +- web-apps/ui/src/views/agent-dev/index.tsx | 1 - web-apps/ui/src/views/agent-flow/index.tsx | 1 - web-apps/ui/src/views/agents/modal/create.tsx | 2 +- web-apps/ui/src/views/debug/debug-drawer.tsx | 2 +- web-apps/ui/src/views/knowledge/index.less | 3 +- web-apps/ui/src/views/knowledge/index.tsx | 1 - web-apps/ui/src/views/plugins/index.less | 118 ++++++++++++ .../src/views/plugins/modal/contribution.ts | 10 + .../ui/src/views/plugins/modal/create.tsx | 171 ++++++++++++++++++ .../ui/src/views/plugins/modal/index.less | 27 +++ web-apps/ui/src/views/plugins/module.ts | 17 ++ web-apps/ui/src/views/plugins/view.tsx | 103 +++++++++++ .../ui/src/views/protal-layout/index.less | 1 + .../ui/src/views/protal-layout/protocol.ts | 10 +- web-apps/ui/src/views/tools/index.less | 11 +- web-apps/ui/src/views/tools/index.tsx | 1 - web-apps/ui/src/views/tools/view.tsx | 77 +------- 42 files changed, 893 insertions(+), 183 deletions(-) create mode 100644 packages/magent-ui/src/magent_ui/routers/plugins/__init__.py create mode 100644 packages/magent-ui/src/magent_ui/routers/plugins/router.py create mode 100644 web-apps/ui/src/common/component/component-model.ts create mode 100644 web-apps/ui/src/common/component/protocol.ts create mode 100644 web-apps/ui/src/components/tag-list/index.less create mode 100644 web-apps/ui/src/components/tag-list/index.tsx create mode 100644 web-apps/ui/src/modules/plugin/icon/index.tsx create mode 100644 web-apps/ui/src/modules/plugin/icon/plugin.svg create mode 100644 web-apps/ui/src/modules/plugin/module.ts create mode 100644 web-apps/ui/src/modules/plugin/plugin-manager.ts create mode 100644 web-apps/ui/src/modules/plugin/plugin-model.ts create mode 100644 web-apps/ui/src/modules/plugin/protocol.ts create mode 100644 web-apps/ui/src/modules/tool/icon/index.tsx create mode 100644 web-apps/ui/src/modules/tool/icon/tool.svg delete mode 100644 web-apps/ui/src/modules/tool/tool-icon.tsx delete mode 100644 web-apps/ui/src/views/agent-config/index.tsx delete mode 100644 web-apps/ui/src/views/agent-dev/index.tsx delete mode 100644 web-apps/ui/src/views/agent-flow/index.tsx delete mode 100644 web-apps/ui/src/views/knowledge/index.tsx create mode 100644 web-apps/ui/src/views/plugins/index.less create mode 100644 web-apps/ui/src/views/plugins/modal/contribution.ts create mode 100644 web-apps/ui/src/views/plugins/modal/create.tsx create mode 100644 web-apps/ui/src/views/plugins/modal/index.less create mode 100644 web-apps/ui/src/views/plugins/module.ts create mode 100644 web-apps/ui/src/views/plugins/view.tsx delete mode 100644 web-apps/ui/src/views/tools/index.tsx diff --git a/packages/magent-ui/src/magent_ui/routers/main.py b/packages/magent-ui/src/magent_ui/routers/main.py index 949f198..53b7a9b 100644 --- a/packages/magent-ui/src/magent_ui/routers/main.py +++ b/packages/magent-ui/src/magent_ui/routers/main.py @@ -7,6 +7,7 @@ from magent_ui.routers.resource.router import resource_router from magent_ui.routers.workflow.router import workflow_router from magent_ui.routers.common.router import common_router +from magent_ui.routers.plugins.router import plugins_router api_router = APIRouter() @@ -18,3 +19,6 @@ api_router.include_router(resource_router, prefix="/v1", tags=["resource"]) api_router.include_router(workflow_router, prefix="/v1", tags=["workflow"]) api_router.include_router(common_router, prefix="/v1", tags=["common"]) +api_router.include_router(plugins_router, prefix="/v1", tags=["plugin"]) + + diff --git a/packages/magent-ui/src/magent_ui/routers/plugins/__init__.py b/packages/magent-ui/src/magent_ui/routers/plugins/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/packages/magent-ui/src/magent_ui/routers/plugins/router.py b/packages/magent-ui/src/magent_ui/routers/plugins/router.py new file mode 100644 index 0000000..f08ecf6 --- /dev/null +++ b/packages/magent-ui/src/magent_ui/routers/plugins/router.py @@ -0,0 +1,16 @@ +from typing import List +from fastapi import APIRouter +from agentuniverse_product.service.plugin_service.plugin_service import PluginService +from agentuniverse_product.service.model.plugin_dto import PluginDTO + +router = APIRouter() +plugins_router = router + + +@router.get("/plugins", response_model=List[PluginDTO]) +async def get_agents(): + return PluginService.get_plugin_list() + +@router.post("/plugins/openapi", response_model=List[PluginDTO]) +async def create_plugin_with_openapi(plugin: PluginDTO): + return PluginService.create_plugin_with_openapi(plugin) diff --git a/web-apps/ui/src/common/component/component-model.ts b/web-apps/ui/src/common/component/component-model.ts new file mode 100644 index 0000000..a94804c --- /dev/null +++ b/web-apps/ui/src/common/component/component-model.ts @@ -0,0 +1,54 @@ +import { prop, transient } from '@difizen/mana-app'; + +import { AsyncModel } from '../async-model.js'; + +import type { ComponentMeta } from './protocol.js'; + +@transient() +export abstract class ComponentModel extends AsyncModel< + T, + O +> { + id: string; + + @prop() + avatar?: string; + + @prop() + nickname: string; + + @prop() + description: string; + + get name(): string { + return this.nickname; + } + set name(v: string) { + this.nickname = v; + } + + protected override fromMeta(option: O): void { + this.id = option.id; + if (option.nickname) { + this.nickname = option.nickname; + } + if (option.description) { + this.description = option.description; + } + if (option.avatar) { + this.avatar = option.avatar; + } + } + + updateOption(option: O) { + this.fromMeta(option); + } + + toMeta = (): ComponentMeta => { + return { + id: this.id, + nickname: this.nickname, + avatar: this.avatar, + }; + }; +} diff --git a/web-apps/ui/src/common/component/protocol.ts b/web-apps/ui/src/common/component/protocol.ts new file mode 100644 index 0000000..a9f020c --- /dev/null +++ b/web-apps/ui/src/common/component/protocol.ts @@ -0,0 +1,6 @@ +export interface ComponentMeta { + id: string; + avatar?: string; + nickname?: string; + description?: string; +} diff --git a/web-apps/ui/src/components/tag-list/index.less b/web-apps/ui/src/components/tag-list/index.less new file mode 100644 index 0000000..f8a4b87 --- /dev/null +++ b/web-apps/ui/src/components/tag-list/index.less @@ -0,0 +1,12 @@ +.tag-list-container { + display: flex; + flex-wrap: nowrap; + overflow: hidden; + align-items: center; + height: 100%; + + .ant-tag { + background: var(--mana-color-border); + font-size: 10px; + } +} diff --git a/web-apps/ui/src/components/tag-list/index.tsx b/web-apps/ui/src/components/tag-list/index.tsx new file mode 100644 index 0000000..372cdd3 --- /dev/null +++ b/web-apps/ui/src/components/tag-list/index.tsx @@ -0,0 +1,73 @@ +import { Tag, Tooltip } from 'antd'; +import { useEffect, useRef, useState } from 'react'; +import './index.less'; + +export interface TagListProps { + tags: string[]; + maxWidth: number; +} +export const TagList: React.FC = ({ tags, maxWidth }: TagListProps) => { + const [visibleTags, setVisibleTags] = useState([]); + const [hiddenTags, setHiddenTags] = useState([]); + const containerRef = useRef(null); + const measurementRef = useRef(null); + + useEffect(() => { + const measureTagWidth = (tag: string) => { + if (measurementRef.current) { + measurementRef.current.innerText = tag; + return measurementRef.current.getBoundingClientRect().width; + } + return 0; + }; + const width = maxWidth - 78; + let currentWidth = 0; + const visible = []; + const hidden = []; + + for (const tag of tags) { + const tagWidth = measureTagWidth(tag) + 8; // 加上 Tag 组件的 padding 和 margin + if (currentWidth + tagWidth <= width) { + visible.push(tag); + currentWidth += tagWidth; + } else { + hidden.push(tag); + } + } + setVisibleTags(visible); + setHiddenTags(hidden); + }, [tags, maxWidth]); + + return ( +
+
+ {visibleTags.map((tag, index) => ( + + {tag} + + ))} + {hiddenTags.length > 0 && ( + + {hiddenTags.map((tag) => ( +
{tag}
+ ))} +
+ } + > + +{hiddenTags.length} more + + )} +
+ ); +}; diff --git a/web-apps/ui/src/modules/agent/agent-model.ts b/web-apps/ui/src/modules/agent/agent-model.ts index bac7593..e0e9a48 100644 --- a/web-apps/ui/src/modules/agent/agent-model.ts +++ b/web-apps/ui/src/modules/agent/agent-model.ts @@ -6,7 +6,7 @@ import { AxiosClient } from '../axios-client/protocol.js'; import type { KnowledgeModelOption } from '../knowledge/protocol.js'; import { LLMManager } from '../model/llm-manager.js'; import type { LLMModel } from '../model/llm-model.js'; -import type { ToolModelOption } from '../tool/protocol.js'; +import type { ToolMeta } from '../tool/protocol.js'; import { ToolManager } from '../tool/tool-manager.js'; import { AgentConfigManager } from './agent-config-manager.js'; @@ -71,7 +71,7 @@ export class AgentModel extends AsyncModel { openingSpeech?: string; @prop() - tool: ToolModelOption[] = []; + tool: ToolMeta[] = []; @prop() knowledge?: KnowledgeModelOption[]; diff --git a/web-apps/ui/src/modules/agent/protocol.ts b/web-apps/ui/src/modules/agent/protocol.ts index 9cd1e57..b366504 100644 --- a/web-apps/ui/src/modules/agent/protocol.ts +++ b/web-apps/ui/src/modules/agent/protocol.ts @@ -1,7 +1,7 @@ import { Syringe } from '@difizen/mana-app'; import type { LLMMeta } from '../model/protocol.js'; -import type { ToolModelOption } from '../tool/protocol.js'; +import type { ToolMeta } from '../tool/protocol.js'; import type { AgentConfig } from './agent-config.js'; import type { AgentModel } from './agent-model.js'; @@ -25,7 +25,7 @@ export interface AgentConfigOption { prompt?: PromptMeta; memory?: string; planner?: PlannerMeta; - tool?: ToolModelOption[]; + tool?: ToolMeta[]; knowledge: any[]; } export const AgentConfigOption = Syringe.defineToken('AgentConfigOption', { @@ -74,7 +74,7 @@ export interface AgentModelOption { prompt?: PromptMeta; memory?: string; planner?: PlannerMeta; - tool?: ToolModelOption[]; + tool?: ToolMeta[]; knowledge?: any[]; } diff --git a/web-apps/ui/src/modules/app.module.ts b/web-apps/ui/src/modules/app.module.ts index c3dcfee..8f97c12 100644 --- a/web-apps/ui/src/modules/app.module.ts +++ b/web-apps/ui/src/modules/app.module.ts @@ -7,6 +7,7 @@ import { AgentsPageModule } from '@/views/agents/module.js'; import { ChatViewModule } from '@/views/chat/module.js'; import { DebugModule } from '@/views/debug/module.js'; import { KnowledgePageModule } from '@/views/knowledge/module.js'; +import { PluginPageModule } from '@/views/plugins/module.js'; import { PortalsModule } from '@/views/protal-layout/module.js'; import { SessionsViewModule } from '@/views/sessions/module.js'; import { ToolPageModule } from '@/views/tools/module.js'; @@ -16,6 +17,7 @@ import { AxiosClientModule } from './axios-client/module.js'; import { BaseLayoutModule } from './base-layout/module.js'; import { ChatMessageModule } from './chat-message/module.js'; import { ModelModule } from './model/module.js'; +import { PluginModule } from './plugin/module.js'; import { SessionModule } from './session/module.js'; import { ToolModule } from './tool/module.js'; @@ -29,6 +31,7 @@ export const AppBaseModule = new ManaModule() AgentBotModule, AxiosClientModule, ToolModule, + PluginModule, ) // 视图模块 .dependOn( @@ -43,6 +46,7 @@ export const AppBaseModule = new ManaModule() PortalsModule, AgentFlowModule, DebugModule, + PluginPageModule, ); export default AppBaseModule; diff --git a/web-apps/ui/src/modules/plugin/icon/index.tsx b/web-apps/ui/src/modules/plugin/icon/index.tsx new file mode 100644 index 0000000..2972b72 --- /dev/null +++ b/web-apps/ui/src/modules/plugin/icon/index.tsx @@ -0,0 +1,20 @@ +import type { AvatarProps } from 'antd'; +import { Avatar } from 'antd'; + +import { toResourceUrl } from '@/common/page-config.js'; + +import icon from './plugin.svg'; + +interface IProps extends AvatarProps { + data?: { avatar?: string; id?: string }; +} +export const PluginIcon = (props: IProps) => { + if (props.data?.avatar) { + return ; + } + return ; +}; + +export const DefaultPluginIcon = () => { + return ; +}; diff --git a/web-apps/ui/src/modules/plugin/icon/plugin.svg b/web-apps/ui/src/modules/plugin/icon/plugin.svg new file mode 100644 index 0000000..845b213 --- /dev/null +++ b/web-apps/ui/src/modules/plugin/icon/plugin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/modules/plugin/module.ts b/web-apps/ui/src/modules/plugin/module.ts new file mode 100644 index 0000000..e79a087 --- /dev/null +++ b/web-apps/ui/src/modules/plugin/module.ts @@ -0,0 +1,26 @@ +import { ManaModule } from '@difizen/mana-app'; + +import { PluginManager } from './plugin-manager.js'; +import { OpenAPIPluginModel, PluginModel } from './plugin-model.js'; +import type { PluginMeta } from './protocol.js'; +import { PluginModelOption } from './protocol.js'; +import { PluginFactory } from './protocol.js'; + +export const PluginModule = ManaModule.create().register( + PluginModel, + PluginManager, + + { + token: PluginFactory, + useFactory: (ctx) => { + return (option: PluginMeta) => { + const child = ctx.container.createChild(); + child.register({ token: PluginModelOption, useValue: option }); + if (option.openapi_desc) { + return child.get(OpenAPIPluginModel); + } + return child.get(PluginModel); + }; + }, + }, +); diff --git a/web-apps/ui/src/modules/plugin/plugin-manager.ts b/web-apps/ui/src/modules/plugin/plugin-manager.ts new file mode 100644 index 0000000..2c523b8 --- /dev/null +++ b/web-apps/ui/src/modules/plugin/plugin-manager.ts @@ -0,0 +1,52 @@ +import { inject, prop, singleton } from '@difizen/mana-app'; + +import { AxiosClient } from '../axios-client/protocol.js'; + +import type { PluginModel } from './plugin-model.js'; +import type { PluginMeta } from './protocol.js'; +import { PluginFactory } from './protocol.js'; + +@singleton() +export class PluginManager { + @inject(PluginFactory) toolFactory: PluginFactory; + @inject(AxiosClient) axios: AxiosClient; + cache: Map = new Map(); + + @prop() + publicList: PluginModel[] = []; + + @prop() + loading = false; + + getAll = async (): Promise => { + const defaultValue: PluginMeta[] = []; + const res = await this.axios.get(`/api/v1/plugins`); + if (res.status === 200) { + return res.data; + } + return defaultValue; + }; + + updatePublic = async () => { + this.loading = true; + const options = await this.getAll(); + this.publicList = options.map(this.getOrCreate); + this.loading = false; + }; + + getOrCreate = (option: PluginMeta): PluginModel => { + const exist = this.cache.get(option.id); + if (exist) { + exist.updateOption(option); + return exist; + } + const tool = this.toolFactory(option); + this.cache.set(tool.id, tool); + return tool; + }; + + create = async (option: PluginMeta) => { + const res = await this.axios.post(`/api/v1/plugins/openapi`, option); + return res; + }; +} diff --git a/web-apps/ui/src/modules/plugin/plugin-model.ts b/web-apps/ui/src/modules/plugin/plugin-model.ts new file mode 100644 index 0000000..512bf98 --- /dev/null +++ b/web-apps/ui/src/modules/plugin/plugin-model.ts @@ -0,0 +1,75 @@ +import { inject, transient } from '@difizen/mana-app'; + +import { ComponentModel } from '@/common/component/component-model.js'; + +import { RequestHelper } from '../axios-client/request.js'; +import { ToolManager } from '../tool/tool-manager.js'; +import type { ToolModel } from '../tool/tool-model.js'; + +import type { PluginMeta } from './protocol.js'; +import { PluginModelOption } from './protocol.js'; + +@transient() +export class PluginModel extends ComponentModel { + protected request: RequestHelper; + protected toolManager: ToolManager; + + option: PluginMeta; + toolset: ToolModel[] = []; + + constructor( + @inject(PluginModelOption) option: PluginMeta, + @inject(ToolManager) toolManager: ToolManager, + @inject(RequestHelper) request: RequestHelper, + ) { + super(); + this.option = option; + this.toolManager = toolManager; + this.request = request; + + this.id = option.id; + this.initialize(option); + } + shouldInitFromMeta(option: PluginMeta): boolean { + return true; + } + fetchInfo(option: PluginMeta): Promise { + throw new Error('Method not implemented.'); + } + + protected override fromMeta(option: PluginMeta): void { + super.fromMeta(option); + this.toolset = option.toolset.map(this.toolManager.getOrCreate); + } + override toMeta = (): PluginMeta => { + return { + ...super.toMeta(), + toolset: this.toolset.map((item) => item.toMeta()), + }; + }; +} + +@transient() +export class OpenAPIPluginModel extends PluginModel { + openapi_desc?: string; + + get openapiDesc(): string | undefined { + return this.openapi_desc; + } + set openapiDesc(v: string | undefined) { + this.openapi_desc = v; + } + + protected override fromMeta(option: PluginMeta): void { + super.fromMeta(option); + this.toolset = option.toolset.map(this.toolManager.getOrCreate); + this.openapi_desc = option.openapi_desc; + } + override toMeta = (): PluginMeta => { + return { + ...super.toMeta(), + toolset: this.toolset.map((item) => item.toMeta()), + openapi_desc: this.openapiDesc, + }; + }; +} diff --git a/web-apps/ui/src/modules/plugin/protocol.ts b/web-apps/ui/src/modules/plugin/protocol.ts new file mode 100644 index 0000000..0c1329b --- /dev/null +++ b/web-apps/ui/src/modules/plugin/protocol.ts @@ -0,0 +1,22 @@ +import { Syringe } from '@difizen/mana-app'; + +import type { ToolMeta } from '../tool/protocol.js'; + +import type { PluginModel } from './plugin-model.js'; + +export interface PluginMeta { + id: string; + avatar?: string; + nickname?: string; + toolset: ToolMeta[]; + openapi_desc?: string; +} + +export const PluginModelOption = Syringe.defineToken('PluginModelOption', { + multiple: false, +}); + +export type PluginFactory = (option: PluginMeta) => PluginModel; +export const PluginFactory = Syringe.defineToken('PluginFactory', { + multiple: false, +}); diff --git a/web-apps/ui/src/modules/tool/icon/index.tsx b/web-apps/ui/src/modules/tool/icon/index.tsx new file mode 100644 index 0000000..0f924b3 --- /dev/null +++ b/web-apps/ui/src/modules/tool/icon/index.tsx @@ -0,0 +1,20 @@ +import type { AvatarProps } from 'antd'; +import { Avatar } from 'antd'; + +import { toResourceUrl } from '@/common/page-config.js'; + +import toolIcon from './tool.svg'; + +interface IProps extends AvatarProps { + data?: { avatar?: string; id?: string }; +} +export const ToolIcon = (props: IProps) => { + if (props.data?.avatar) { + return ; + } + return ; +}; + +export const DefaultToolIcon = () => { + return ; +}; diff --git a/web-apps/ui/src/modules/tool/icon/tool.svg b/web-apps/ui/src/modules/tool/icon/tool.svg new file mode 100644 index 0000000..4c9b81c --- /dev/null +++ b/web-apps/ui/src/modules/tool/icon/tool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-apps/ui/src/modules/tool/protocol.ts b/web-apps/ui/src/modules/tool/protocol.ts index 6091cac..61adc74 100644 --- a/web-apps/ui/src/modules/tool/protocol.ts +++ b/web-apps/ui/src/modules/tool/protocol.ts @@ -39,7 +39,7 @@ export const ToolConfigType = { export type { ToolModel } from './tool-model.js'; -export interface ToolModelOption { +export interface ToolMeta { id: string; nickname: string; avatar: string; @@ -51,13 +51,13 @@ export const ToolModelOption = Syringe.defineToken('ToolModelOption', { multiple: false, }); -export type ToolFactory = (options: ToolModelOption) => ToolModel; +export type ToolFactory = (options: ToolMeta) => ToolModel; export const ToolFactory = Syringe.defineToken('ToolFactory', { multiple: false, }); export const ToolModelType = { - isOption(data?: Record): data is ToolModelOption { + isOption(data?: Record): data is ToolMeta { return !!(data && 'id' in data); }, isFullOption(data?: Record): boolean { diff --git a/web-apps/ui/src/modules/tool/tool-icon.tsx b/web-apps/ui/src/modules/tool/tool-icon.tsx deleted file mode 100644 index bc982b9..0000000 --- a/web-apps/ui/src/modules/tool/tool-icon.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import type { AvatarProps } from 'antd'; -import { Avatar } from 'antd'; - -import { toResourceUrl } from '@/common/page-config.js'; - -interface IProps extends AvatarProps { - data: { avatar?: string; id?: string }; -} -export const ToolIcon = (props: IProps) => { - if (props.data.avatar) { - return ; - } - return } />; -}; - -export const DefaultToolIcon = () => { - return ( - - - - - - - - - - ); -}; diff --git a/web-apps/ui/src/modules/tool/tool-manager.ts b/web-apps/ui/src/modules/tool/tool-manager.ts index 5129748..e1c95a6 100644 --- a/web-apps/ui/src/modules/tool/tool-manager.ts +++ b/web-apps/ui/src/modules/tool/tool-manager.ts @@ -2,7 +2,8 @@ import { inject, singleton } from '@difizen/mana-app'; import { AxiosClient } from '../axios-client/protocol.js'; -import { ToolFactory, type ToolModel, type ToolModelOption } from './protocol.js'; +import type { ToolMeta } from './protocol.js'; +import { ToolFactory, type ToolModel } from './protocol.js'; @singleton() export class ToolManager { @@ -10,18 +11,19 @@ export class ToolManager { @inject(ToolFactory) toolFactory: ToolFactory; @inject(AxiosClient) axios: AxiosClient; - getAll = async (): Promise => { - const defaultValue: ToolModelOption[] = []; - const res = await this.axios.get(`/api/v1/tools`); + getAll = async (): Promise => { + const defaultValue: ToolMeta[] = []; + const res = await this.axios.get(`/api/v1/tools`); if (res.status === 200) { return res.data; } return defaultValue; }; - getOrCreate = (option: ToolModelOption): ToolModel => { + getOrCreate = (option: ToolMeta): ToolModel => { const exist = this.cache.get(option.id); if (exist) { + exist.updateOption(option); return exist; } const tool = this.toolFactory(option); diff --git a/web-apps/ui/src/modules/tool/tool-model.ts b/web-apps/ui/src/modules/tool/tool-model.ts index d668636..faa4561 100644 --- a/web-apps/ui/src/modules/tool/tool-model.ts +++ b/web-apps/ui/src/modules/tool/tool-model.ts @@ -1,14 +1,16 @@ import { Deferred, inject, prop, transient } from '@difizen/mana-app'; import { AsyncModel } from '@/common/async-model.js'; + import { AxiosClient } from '../axios-client/protocol.js'; +import type { ToolMeta } from './protocol.js'; import { ToolModelOption, ToolModelType } from './protocol.js'; import { ToolConfigManager } from './tool-config-manager.js'; import type { ToolConfig } from './tool-config.js'; @transient() -export class ToolModel extends AsyncModel { +export class ToolModel extends AsyncModel { axios: AxiosClient; configManager: ToolConfigManager; @@ -29,10 +31,10 @@ export class ToolModel extends AsyncModel { return this.draftDeferred.promise; } - option: ToolModelOption; + option: ToolMeta; constructor( - @inject(ToolModelOption) option: ToolModelOption, + @inject(ToolModelOption) option: ToolMeta, @inject(ToolConfigManager) configManager: ToolConfigManager, @inject(AxiosClient) axios: AxiosClient, ) { @@ -49,29 +51,37 @@ export class ToolModel extends AsyncModel { return true; } - updateOption(option: ToolModelOption) { - // TODO: + updateOption(option: ToolMeta) { + this.fromMeta(option); } - protected override fromMeta(option: ToolModelOption = this.option) { + protected override fromMeta(option: ToolMeta = this.option) { this.id = option.id; - this.nickname = option.nickname; - this.avatar = option.avatar; - this.description = option.description; - this.parameters = option.parameters; + if (option.nickname) { + this.nickname = option.nickname; + } + if (option.description) { + this.description = option.description; + } + if (option.avatar) { + this.avatar = option.avatar; + } + if (option.parameters.length > 0) { + this.parameters = option.parameters; + } if (ToolModelType.isFullOption(option)) { super.fromMeta(option); } } - async fetchInfo(option: ToolModelOption = this.option) { - const res = await this.axios.get(`api/v1/tools/${option.id}`); + async fetchInfo(option: ToolMeta = this.option) { + const res = await this.axios.get(`api/v1/tools/${option.id}`); if (res.status === 200) { this.fromMeta(res.data); } } - toMeta(): ToolModelOption { + toMeta(): ToolMeta { return { id: this.id, nickname: this.nickname, diff --git a/web-apps/ui/src/views/agent-config/index.tsx b/web-apps/ui/src/views/agent-config/index.tsx deleted file mode 100644 index fd3c604..0000000 --- a/web-apps/ui/src/views/agent-config/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './module.js'; diff --git a/web-apps/ui/src/views/agent-config/tools-modal/modal.tsx b/web-apps/ui/src/views/agent-config/tools-modal/modal.tsx index 89a6cb5..3ec0456 100644 --- a/web-apps/ui/src/views/agent-config/tools-modal/modal.tsx +++ b/web-apps/ui/src/views/agent-config/tools-modal/modal.tsx @@ -6,9 +6,10 @@ import type { TableRowSelection } from 'antd/es/table/interface.js'; import { useMemo } from 'react'; import type { AgentModel } from '@/modules/agent/protocol.js'; -import type { ToolModelOption } from '@/modules/tool/protocol.js'; -import { ToolIcon } from '@/modules/tool/tool-icon.js'; +import type { ToolMeta } from '@/modules/tool/protocol.js'; +import { ToolIcon } from '@/modules/tool/icon/index.js'; import { ToolSpace } from '@/modules/tool/tool-space.js'; + import { ToolsModalId } from '../protocol.js'; export const ToolsModalComponent = (props: ModalItemProps<{ agent: AgentModel }>) => { @@ -17,7 +18,7 @@ export const ToolsModalComponent = (props: ModalItemProps<{ agent: AgentModel }> const { agent } = props.data || {}; const columns = useMemo(() => { - const c: TableColumnsType = [ + const c: TableColumnsType = [ { title: 'id', dataIndex: 'id', @@ -61,7 +62,7 @@ export const ToolsModalComponent = (props: ModalItemProps<{ agent: AgentModel }> .map((item) => item.toMeta()); }; - const rowSelection: TableRowSelection = { + const rowSelection: TableRowSelection = { selectedRowKeys: (agent.tool || []).map((item) => item.id), onChange: onSelectChange, }; @@ -74,7 +75,7 @@ export const ToolsModalComponent = (props: ModalItemProps<{ agent: AgentModel }> title="选择工具" footer={null} > - + loading={toolSpace.loading} rowSelection={rowSelection} dataSource={toolSpace.list} diff --git a/web-apps/ui/src/views/agent-config/view.tsx b/web-apps/ui/src/views/agent-config/view.tsx index ef7ae37..60af212 100644 --- a/web-apps/ui/src/views/agent-config/view.tsx +++ b/web-apps/ui/src/views/agent-config/view.tsx @@ -18,7 +18,7 @@ import type { AgentModel } from '@/modules/agent/protocol.js'; import { KnowledgeIcon } from '@/modules/knowledge/knowledge-icon.js'; import type { KnowledgeModelOption } from '@/modules/knowledge/protocol.js'; import { ModelSelector } from '@/modules/model/model-selector/index.js'; -import { ToolIcon } from '@/modules/tool/tool-icon.js'; +import { ToolIcon } from '@/modules/tool/icon/index.js'; import { CharacterSetting } from './components/character-setting/index.js'; import { ConfigList } from './components/config-selector/index.js'; diff --git a/web-apps/ui/src/views/agent-dev/index.tsx b/web-apps/ui/src/views/agent-dev/index.tsx deleted file mode 100644 index fd3c604..0000000 --- a/web-apps/ui/src/views/agent-dev/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './module.js'; diff --git a/web-apps/ui/src/views/agent-flow/index.tsx b/web-apps/ui/src/views/agent-flow/index.tsx deleted file mode 100644 index fd3c604..0000000 --- a/web-apps/ui/src/views/agent-flow/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './module.js'; diff --git a/web-apps/ui/src/views/agents/modal/create.tsx b/web-apps/ui/src/views/agents/modal/create.tsx index 6f546ef..2ed8537 100644 --- a/web-apps/ui/src/views/agents/modal/create.tsx +++ b/web-apps/ui/src/views/agents/modal/create.tsx @@ -186,7 +186,7 @@ export const AgentModalComponent = (props: ModalItemProps) => { /> - + diff --git a/web-apps/ui/src/views/debug/debug-drawer.tsx b/web-apps/ui/src/views/debug/debug-drawer.tsx index 430f88a..1632d19 100644 --- a/web-apps/ui/src/views/debug/debug-drawer.tsx +++ b/web-apps/ui/src/views/debug/debug-drawer.tsx @@ -9,7 +9,7 @@ import { useState } from 'react'; import { copy2clipboard } from '@/common/utils.js'; import { DefaultLLMIcon } from '@/modules/model/model-icon/index.js'; -import { DefaultToolIcon } from '@/modules/tool/tool-icon.js'; +import { DefaultToolIcon } from '@/modules/tool/icon/index.js'; import { HumanIcon } from '../chat/components/message/human-message.js'; import type { ChatView } from '../chat/view.js'; diff --git a/web-apps/ui/src/views/knowledge/index.less b/web-apps/ui/src/views/knowledge/index.less index d94915e..06e3675 100644 --- a/web-apps/ui/src/views/knowledge/index.less +++ b/web-apps/ui/src/views/knowledge/index.less @@ -1,13 +1,12 @@ .magent-knowledge { height: calc(100% - 24px); margin: 0 24px; - background-color: var(--mana-color-bg-container); border-radius: 8px; &-list-header { padding: 0 0 0 24px; height: 48px; - border-bottom: 1px solid var(--mana-color-border-secondary); + border-bottom: 1px solid var(--mana-ant-color-border); &-label { display: flex; diff --git a/web-apps/ui/src/views/knowledge/index.tsx b/web-apps/ui/src/views/knowledge/index.tsx deleted file mode 100644 index fd3c604..0000000 --- a/web-apps/ui/src/views/knowledge/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './module.js'; diff --git a/web-apps/ui/src/views/plugins/index.less b/web-apps/ui/src/views/plugins/index.less new file mode 100644 index 0000000..e7933b4 --- /dev/null +++ b/web-apps/ui/src/views/plugins/index.less @@ -0,0 +1,118 @@ +.magent-plugins { + height: calc(100% - 24px); + margin: 0 24px; + border-radius: 8px; + + &-creation { + position: absolute; + top: 0; + right: 24px; + height: 64px; + display: flex; + align-items: center; + + button { + border: none; + } + } + + &-list-header { + padding: 0 0 0 24px; + height: 48px; + border-bottom: 1px solid var(--mana-ant-color-border); + + &-label { + display: flex; + align-items: center; + color: black; + font-size: 16px; + } + + &-label + &-label { + padding-left: 24px; + } + } + + &-list { + height: calc(100% - 48px); + padding-top: 12px; + + &-item { + display: block; + } + + &-item + &-item { + padding-left: 24px; + } + + &-row { + padding-inline: 6px; + border-radius: 6px; + + &:not(:last-child) &-content { + border-bottom: 1px solid var(--mana-ant-color-bg-text-hover); + } + + &-content { + padding-left: 18px; + width: 100%; + display: flex; + } + + &:hover { + background-color: var(--mana-ant-color-bg-text-hover); + } + + &:hover &-content { + border-bottom: 1px solid transparent; + } + } + } + + .ant-spin-nested-loading, + .ant-spin-container, + .ant-list-items { + height: 100%; + } + + .ant-list-items { + padding-bottom: 24px; + overflow-y: auto; + } + + .ant-list .ant-list-item .ant-list-item-meta .ant-list-item-meta-content { + width: 100%; + } + + .ant-list-item-meta-avatar { + background: var(--mana-ant-color-bg-container); + border: 1px solid var(--mana-ant-color-bg-container-disabled); + border-radius: 8px; + align-items: center; + display: inline-flex; + justify-content: center; + overflow: hidden; + position: relative; + } + + .tool-lists-label { + display: flex; + justify-content: space-between; + } + + .ant-checkbox-wrapper { + width: 100%; + } +} + +.button-container { + display: flex; + align-items: center; + height: 100%; +} + +.tool-lists-label-item { + color: black; + font-size: 16px; + padding-bottom: 12px; +} diff --git a/web-apps/ui/src/views/plugins/modal/contribution.ts b/web-apps/ui/src/views/plugins/modal/contribution.ts new file mode 100644 index 0000000..14dc755 --- /dev/null +++ b/web-apps/ui/src/views/plugins/modal/contribution.ts @@ -0,0 +1,10 @@ +import { ModalContribution, singleton } from '@difizen/mana-app'; + +import { PluginCreateModal } from './create.js'; + +@singleton({ contrib: [ModalContribution] }) +export class PluginModalContribution implements ModalContribution { + registerModal() { + return PluginCreateModal; + } +} diff --git a/web-apps/ui/src/views/plugins/modal/create.tsx b/web-apps/ui/src/views/plugins/modal/create.tsx new file mode 100644 index 0000000..198106c --- /dev/null +++ b/web-apps/ui/src/views/plugins/modal/create.tsx @@ -0,0 +1,171 @@ +import path from 'path'; + +import type { ModalItem, ModalItemProps } from '@difizen/mana-app'; +import { useInject } from '@difizen/mana-app'; +import type { FormInstance } from 'antd'; +import { Button, Form, Input, Space } from 'antd'; +import { Modal } from 'antd'; +import type { PropsWithChildren } from 'react'; +import { useEffect, useState } from 'react'; + +import { AvatarUpload } from '@/components/avatar-upload/index.js'; +import { RequestHelper } from '@/modules/axios-client/request.js'; +import { PluginIcon } from '@/modules/plugin/icon/index.js'; +import './index.less'; +import { PluginManager } from '@/modules/plugin/plugin-manager.js'; + +export const PluginCreateModalId = 'magent-plugin-creation'; +interface SubmitButtonProps { + form: FormInstance; +} + +const SubmitButton: React.FC> = ( + props: PropsWithChildren, +) => { + const { form, children } = props; + const [submittable, setSubmittable] = useState(false); + + const values = Form.useWatch([], form); + + useEffect(() => { + form + .validateFields({ + validateOnly: true, + }) + .then(() => setSubmittable(true)) + .catch(() => setSubmittable(false)); + }, [form, values]); + + return ( + + ); +}; + +const UploadButton = (props: { imageUrl?: string }) => { + const { imageUrl } = props; + return imageUrl ? ( + + ) : ( + + ); +}; + +export const PluginModalComponent = (props: ModalItemProps) => { + const pluginManager = useInject(PluginManager); + const req = useInject(RequestHelper); + const { visible, close } = props; + const [form] = Form.useForm<{ + id: string; + avatar?: string; + nickname: string; + description?: string; + openapi_desc: string; + }>(); + const idValue = Form.useWatch('id', form); + + return ( + close()} + width={640} + title="新建插件" + footer={ + + + 确认 + + } + > +
{ + const meta = { + id: values.id, + nickname: values.nickname, + avatar: values.avatar, + description: values.description, + openapi_desc: values.openapi_desc, + toolset: [], + }; + const res = await pluginManager.create(meta); + if (res.status === 200) { + close(); + pluginManager.updatePublic(); + } + }} + onFinishFailed={console.error} + initialValues={{ plannerId: 'rag_planner' }} + > + ({ + async validator(_, value) { + const res = await req.get(`/api/v1/common/is_id_unique`, { + id: value, + type: 'tool', + }); + if (res.status !== 200 || res.data === false) { + throw new Error(`${value} 已存在,请更换其他 id`); + } + }, + }), + ]} + > + + + + + + + + + + + { + const extname = path.extname(file.name); + const filename = `${idValue}${extname}`; + return { + file, + filename, + }; + }} + AvatarRender={UploadButton} + /> + + + + +
+
+ ); +}; + +export const PluginCreateModal: ModalItem = { + id: PluginCreateModalId, + component: PluginModalComponent, +}; diff --git a/web-apps/ui/src/views/plugins/modal/index.less b/web-apps/ui/src/views/plugins/modal/index.less new file mode 100644 index 0000000..ff679de --- /dev/null +++ b/web-apps/ui/src/views/plugins/modal/index.less @@ -0,0 +1,27 @@ +.magent-plugin-creation { + &-form { + padding: 24px 0; + + input { + border-color: var(--mana-ant-color-border-secondary); + } + + textarea { + border-color: var(--mana-ant-color-border-secondary); + } + } + + .ant-modal-content { + background-color: var(--mana-ant-color-bg-layout); + + .ant-modal-header { + background: transparent; + } + + .ant-modal-footer { + button { + border: none; + } + } + } +} diff --git a/web-apps/ui/src/views/plugins/module.ts b/web-apps/ui/src/views/plugins/module.ts new file mode 100644 index 0000000..b79f79d --- /dev/null +++ b/web-apps/ui/src/views/plugins/module.ts @@ -0,0 +1,17 @@ +import { + createSlotPreference, + createViewPreference, + ManaModule, +} from '@difizen/mana-app'; + +import { PluginModalContribution } from './modal/contribution.js'; +import { PluginsView, slot } from './view.js'; + +export const PluginPageModule = ManaModule.create().register( + PluginsView, + PluginModalContribution, + createSlotPreference({ + slot: slot, + view: PluginsView, + }), +); diff --git a/web-apps/ui/src/views/plugins/view.tsx b/web-apps/ui/src/views/plugins/view.tsx new file mode 100644 index 0000000..9c6d944 --- /dev/null +++ b/web-apps/ui/src/views/plugins/view.tsx @@ -0,0 +1,103 @@ +/* eslint-disable react/prop-types */ +import { + BaseView, + ViewInstance, + inject, + singleton, + useInject, + view, + ModalService, +} from '@difizen/mana-app'; +import { Button, Col, List, Row } from 'antd'; +import { forwardRef } from 'react'; + +import { TagList } from '@/components/tag-list/index.js'; +import { PluginManager } from '@/modules/plugin/plugin-manager.js'; +import { ToolIcon } from '@/modules/tool/icon/index.js'; + +import { PluginCreateModalId } from './modal/create.js'; +import './index.less'; + +export interface ToolItem { + nickname: string; + id: string; + avatar: string; + description: string; + parameters: string[]; +} + +const viewId = 'magent-plugins'; +export const slot = `${viewId}-slot`; + +const PluginsViewComponent = forwardRef( + function PluginsViewComponent(props, ref) { + const instance = useInject(ViewInstance); + const plugins = useInject(PluginManager); + const modalService = useInject(ModalService); + + return ( +
+ + + 插件 + + + 工具 + + + 操作 + + + ( +
+ + + + } + title={item.nickname} + description={item.description} + /> + + + + item.id)} + maxWidth={400} + > + + + +
+ )} + /> +
+ +
+
+ ); + }, +); + +@singleton() +@view(viewId) +export class PluginsView extends BaseView { + override view = PluginsViewComponent; + + @inject(PluginManager) pluginManager: PluginManager; + + override async onViewMount(): Promise { + this.pluginManager.updatePublic(); + } +} diff --git a/web-apps/ui/src/views/protal-layout/index.less b/web-apps/ui/src/views/protal-layout/index.less index c1f7e87..3d58f44 100644 --- a/web-apps/ui/src/views/protal-layout/index.less +++ b/web-apps/ui/src/views/protal-layout/index.less @@ -2,6 +2,7 @@ height: 100%; box-sizing: border-box; position: relative; + background-color: var(--mana-ant-color-bg-layout); .ant-segmented-item + .ant-segmented-item { margin-left: 18px; diff --git a/web-apps/ui/src/views/protal-layout/protocol.ts b/web-apps/ui/src/views/protal-layout/protocol.ts index d35d449..738964b 100644 --- a/web-apps/ui/src/views/protal-layout/protocol.ts +++ b/web-apps/ui/src/views/protal-layout/protocol.ts @@ -6,15 +6,19 @@ interface Portal { export const portals: Portal[] = [ { path: 'agents', - label: 'Agents', + label: '智能体', }, { path: 'tools', - label: 'Tools', + label: '工具', + }, + { + path: 'plugins', + label: '插件', }, { path: 'knowledge', - label: 'Knowledge', + label: '知识', }, // { // path: 'debug', diff --git a/web-apps/ui/src/views/tools/index.less b/web-apps/ui/src/views/tools/index.less index ac531f6..c18ac7e 100644 --- a/web-apps/ui/src/views/tools/index.less +++ b/web-apps/ui/src/views/tools/index.less @@ -1,13 +1,12 @@ .magent-tools { height: calc(100% - 24px); - background-color: var(--mana-color-bg-container); margin: 0 24px; border-radius: 8px; &-list-header { padding: 0 0 0 24px; height: 48px; - border-bottom: 1px solid var(--mana-color-border-secondary); + border-bottom: 1px solid var(--mana-ant-color-border); &-label { display: flex; @@ -59,14 +58,6 @@ } } -.tag-list-container { - display: flex; - flex-wrap: nowrap; - overflow: hidden; - align-items: center; - height: 100%; -} - .button-container { display: flex; align-items: center; diff --git a/web-apps/ui/src/views/tools/index.tsx b/web-apps/ui/src/views/tools/index.tsx deleted file mode 100644 index fd3c604..0000000 --- a/web-apps/ui/src/views/tools/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './module.js'; diff --git a/web-apps/ui/src/views/tools/view.tsx b/web-apps/ui/src/views/tools/view.tsx index 17a06ad..b5ee433 100644 --- a/web-apps/ui/src/views/tools/view.tsx +++ b/web-apps/ui/src/views/tools/view.tsx @@ -3,7 +3,6 @@ import { BaseView, ViewInstance, inject, - prop, singleton, useInject, view, @@ -12,7 +11,9 @@ import { Col, List, Row, Tag, Tooltip } from 'antd'; import { forwardRef, useEffect, useRef, useState } from 'react'; import './index.less'; -import { ToolIcon } from '@/modules/tool/tool-icon.js'; +import { TagList } from '@/components/tag-list/index.js'; +import { PluginManager } from '@/modules/plugin/plugin-manager.js'; +import { ToolIcon } from '@/modules/tool/icon/index.js'; import { ToolSpace } from '@/modules/tool/tool-space.js'; export interface ToolItem { @@ -26,73 +27,6 @@ export interface ToolItem { const viewId = 'magent-tools'; export const slot = `${viewId}-slot`; -const TagList: React.FC<{ - tags: string[]; - maxWidth: number; -}> = ({ tags, maxWidth }) => { - const [visibleTags, setVisibleTags] = useState([]); - const [hiddenTags, setHiddenTags] = useState([]); - const containerRef = useRef(null); - const measurementRef = useRef(null); - - useEffect(() => { - const measureTagWidth = (tag: string) => { - if (measurementRef.current) { - measurementRef.current.innerText = tag; - return measurementRef.current.getBoundingClientRect().width; - } - return 0; - }; - const width = maxWidth - 78; - let currentWidth = 0; - const visible = []; - const hidden = []; - - for (const tag of tags) { - const tagWidth = measureTagWidth(tag) + 8; // 加上 Tag 组件的 padding 和 margin - if (currentWidth + tagWidth <= width) { - visible.push(tag); - currentWidth += tagWidth; - } else { - hidden.push(tag); - } - } - setVisibleTags(visible); - setHiddenTags(hidden); - }, [tags, maxWidth]); - - return ( -
-
- {visibleTags.map((tag, index) => ( - {tag} - ))} - {hiddenTags.length > 0 && ( - - {hiddenTags.map((tag) => ( -
{tag}
- ))} -
- } - > - +{hiddenTags.length} more - - )} -
- ); -}; - const ToolsViewComponent = forwardRef( function ToolsViewComponent(props, ref) { const instance = useInject(ViewInstance); @@ -142,14 +76,11 @@ const ToolsViewComponent = forwardRef( @view(viewId) export class ToolsView extends BaseView { override view = ToolsViewComponent; - @prop() - loadig = false; @inject(ToolSpace) toolSpace: ToolSpace; + @inject(PluginManager) pluginManager: PluginManager; override async onViewMount(): Promise { - this.loadig = true; await this.toolSpace.update(); - this.loadig = false; } } From 288145437bb4e86aa586397c853de770d430ea6c Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Fri, 30 Aug 2024 06:24:42 +0800 Subject: [PATCH 28/78] fix: workflow save and read --- .../src/magent_ui/routers/agents/router.py | 2 +- .../src/magent_ui/routers/workflow/router.py | 2 +- web-apps/ui/src/modules/agent/protocol.ts | 6 +- .../ui/src/modules/axios-client/request.ts | 12 +- .../ui/src/modules/model/model-icon/index.tsx | 9 +- web-apps/ui/src/modules/planner/protocol.ts | 9 ++ web-apps/ui/src/modules/workflow/nodes.yaml | 42 +++++++ web-apps/ui/src/modules/workflow/protocol.ts | 31 +++++ .../src/views/agent-flow/agent-flow-view.tsx | 116 +++++++++++++++--- .../ui/src/views/agent-flow/flow-utils.ts | 10 +- web-apps/ui/src/views/agent-flow/toolbar.tsx | 9 +- .../magent-flow/src/components/Flow/index.tsx | 3 +- .../src/stores/useKnowledgeStore.ts | 3 +- .../magent-flow/src/stores/useModelStore.ts | 3 +- .../src/stores/useShortcutsStore.ts | 3 +- 15 files changed, 214 insertions(+), 46 deletions(-) create mode 100644 web-apps/ui/src/modules/planner/protocol.ts create mode 100644 web-apps/ui/src/modules/workflow/nodes.yaml create mode 100644 web-apps/ui/src/modules/workflow/protocol.ts diff --git a/packages/magent-ui/src/magent_ui/routers/agents/router.py b/packages/magent-ui/src/magent_ui/routers/agents/router.py index 751d080..a790a33 100644 --- a/packages/magent-ui/src/magent_ui/routers/agents/router.py +++ b/packages/magent-ui/src/magent_ui/routers/agents/router.py @@ -39,7 +39,7 @@ async def create_workflow_agent(agent: AgentDTO): workflow_id = f"{agent.id}_workflow" workflow_name = f"{agent.nickname}_workflow" workflow = WorkflowDTO(id=workflow_id, name=workflow_name) - WorkflowService.create_workflow(workflow) + workflow_id = WorkflowService.create_workflow(workflow) agent.planner = PlannerDTO(id='workflow_planner', workflow_id=workflow_id) return AgentService.create_agent(agent) diff --git a/packages/magent-ui/src/magent_ui/routers/workflow/router.py b/packages/magent-ui/src/magent_ui/routers/workflow/router.py index 2235c83..cd1af1c 100644 --- a/packages/magent-ui/src/magent_ui/routers/workflow/router.py +++ b/packages/magent-ui/src/magent_ui/routers/workflow/router.py @@ -11,7 +11,7 @@ async def get_agent_detail(workflow_id): return WorkflowService.get_workflow_detail(workflow_id) -@router.put("/workflows/{workflow_id}", response_model=WorkflowDTO | None) +@router.put("/workflows/{workflow_id}", response_model=str | None) async def update_agent(workflow_id, workflow: WorkflowDTO): return WorkflowService.update_workflow(workflow) diff --git a/web-apps/ui/src/modules/agent/protocol.ts b/web-apps/ui/src/modules/agent/protocol.ts index b366504..73255ed 100644 --- a/web-apps/ui/src/modules/agent/protocol.ts +++ b/web-apps/ui/src/modules/agent/protocol.ts @@ -1,6 +1,7 @@ import { Syringe } from '@difizen/mana-app'; import type { LLMMeta } from '../model/protocol.js'; +import type { PlannerMeta } from '../planner/protocol.js'; import type { ToolMeta } from '../tool/protocol.js'; import type { AgentConfig } from './agent-config.js'; @@ -8,11 +9,6 @@ import type { AgentModel } from './agent-model.js'; export type { AgentConfig } from './agent-config.js'; -export interface PlannerMeta { - id: string; - nickname: string; - members?: AgentModelOption[]; -} export interface PromptMeta { introduction: string; target: string; diff --git a/web-apps/ui/src/modules/axios-client/request.ts b/web-apps/ui/src/modules/axios-client/request.ts index f63bc8a..cde5232 100644 --- a/web-apps/ui/src/modules/axios-client/request.ts +++ b/web-apps/ui/src/modules/axios-client/request.ts @@ -6,8 +6,16 @@ import { AxiosClient } from './protocol.js'; @singleton() export class RequestHelper { @inject(AxiosClient) axios: AxiosClient; - get(basePath: string, params: Record) { + get = (basePath: string, params: Record) => { const query = qs.stringify(params); return this.axios.get(`${basePath}?${query}`); - } + }; + + post = async (url: string, data: any) => { + return this.axios.post(url, data); + }; + + put = async (url: string, data: any) => { + return this.axios.put(url, data); + }; } diff --git a/web-apps/ui/src/modules/model/model-icon/index.tsx b/web-apps/ui/src/modules/model/model-icon/index.tsx index 2b64cdb..4705c6d 100644 --- a/web-apps/ui/src/modules/model/model-icon/index.tsx +++ b/web-apps/ui/src/modules/model/model-icon/index.tsx @@ -31,10 +31,13 @@ export const DefaultLLMIcon = () => { }; const match = (data: LLMMeta, name: string): boolean => { + const labels = [data.id, data.nickname, data.model_name?.[0]]; + if ( - data.id.toLowerCase().includes(name) || - data.nickname.toLowerCase().includes(name) || - data.model_name[0].toLowerCase().includes(name) + labels + .filter((item) => !!item) + .map((item) => item.toLowerCase()) + .find((item) => item.includes(name)) ) { return true; } diff --git a/web-apps/ui/src/modules/planner/protocol.ts b/web-apps/ui/src/modules/planner/protocol.ts new file mode 100644 index 0000000..31ea6ab --- /dev/null +++ b/web-apps/ui/src/modules/planner/protocol.ts @@ -0,0 +1,9 @@ +export interface PlannerMeta { + id: string; + nickname: string; + members?: string[]; +} + +export interface WorkflowPlannerMeta extends PlannerMeta { + workflow_id: string; +} diff --git a/web-apps/ui/src/modules/workflow/nodes.yaml b/web-apps/ui/src/modules/workflow/nodes.yaml new file mode 100644 index 0000000..871a52b --- /dev/null +++ b/web-apps/ui/src/modules/workflow/nodes.yaml @@ -0,0 +1,42 @@ +nodes: + - id: start-e943701d-1e3c-4bd5-875f-af3be9cef708 + name: 开始节点 + description: 工作流的起始节点,用于设定启动工作流需要的信息 + type: start + position: + x: 390 + 'y': 90 + data: + outputs: + - name: user_input + type: string + description: 用户本轮对话输入内容 + - id: end-a8dbad06-88c8-4efd-983c-096d2ad3e588 + position: + x: 1102.8851405233877 + 'y': 69.68638988895759 + name: 结束节点 + description: 工作流的最终节点,用于返回工作流运行后的结果信息 + type: end + data: + inputs: + input_param: + - name: response + type: string + value: + type: reference + prompt: + name: response + type: string + description: 输出内容 + value: + type: reference + content: '{{response}}' + outputs: + - name: output + type: string +edges: + - id: >- + xy-edge__end-a8dbad06-88c8-4efd-983c-096d2ad3e588-start-e943701d-1e3c-4bd5-875f-af3be9cef708 + source_node_id: end-a8dbad06-88c8-4efd-983c-096d2ad3e588 + target_node_id: start-e943701d-1e3c-4bd5-875f-af3be9cef708 diff --git a/web-apps/ui/src/modules/workflow/protocol.ts b/web-apps/ui/src/modules/workflow/protocol.ts new file mode 100644 index 0000000..d95fd33 --- /dev/null +++ b/web-apps/ui/src/modules/workflow/protocol.ts @@ -0,0 +1,31 @@ +import type { Edge, NodeType } from '@difizen/magent-flow'; + +import type { ComponentMeta } from '@/common/component/protocol.js'; + +// export interface Edge { +// source_node_id: string; +// target_node_id: string; +// id: string; +// } + +export interface Posiotion { + x: number; + y: number; +} +export interface Node { + id: string; + name: string; + description: string; + type: string; + position: Posiotion; + data?: any; +} + +export interface Graph { + edges: Edge[]; + nodes: NodeType[]; +} + +export interface WorkflowMeta extends ComponentMeta { + graph: Graph; +} diff --git a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx index 073a8bd..f9bc19d 100644 --- a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx +++ b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx @@ -1,17 +1,29 @@ import { DeleteOutlined } from '@ant-design/icons'; import type { BasicSchema } from '@difizen/magent-flow'; import { useFlowStore, useKnowledgeStore, useModelStore } from '@difizen/magent-flow'; -import { BaseView, inject, prop, view, ViewOption, transient } from '@difizen/mana-app'; +import { + BaseView, + inject, + prop, + view, + ViewOption, + transient, + useInject, + ViewInstance, +} from '@difizen/mana-app'; import { Button } from 'antd'; -import yaml from 'js-yaml'; +// import yaml from 'js-yaml'; import { forwardRef, useEffect, useState } from 'react'; import { AgentManager } from '@/modules/agent/agent-manager.js'; import type { AgentModel } from '@/modules/agent/protocol.js'; import './index.less'; +import { RequestHelper } from '@/modules/axios-client/request.js'; import type { KnowledgeModelOption } from '@/modules/knowledge/protocol.js'; import { ModelSelector } from '@/modules/model/model-selector/index.js'; import type { LLMMeta } from '@/modules/model/protocol.js'; +import type { WorkflowPlannerMeta } from '@/modules/planner/protocol.js'; +import type { Graph, WorkflowMeta } from '@/modules/workflow/protocol.js'; import { KnowledgeModal, @@ -29,6 +41,7 @@ const AgentFlowComponent = forwardRef( const { setModelSelector } = useModelStore(); const { setKnowledgeSelector } = useKnowledgeStore(); const { setNode, initFlow } = useFlowStore(); + const instance = useInject(ViewInstance); useEffect(() => { // 注册 flow 中模型选择 @@ -225,26 +238,52 @@ const AgentFlowComponent = forwardRef( }, [setKnowledgeSelector, setModelSelector, setNode]); useEffect(() => { - const mockGraph = localStorage.getItem('magent_flow_testdata'); - if (!mockGraph) { - return; - } - const graph = yaml.load(mockGraph); - const nodes = graph.nodes.map((n) => { - return InitNodeParser(n); - }); + instance + .getGraphInfo() + .then((info) => { + // const graph = yaml.load(mockGraph) as Graph; + const graph = info.graph || { nodes: [], edges: [] }; + const nodes = graph.nodes.map((n) => { + return InitNodeParser(n); + }); + + const edges = graph.edges.map((e) => { + return InitEdgeParser(e); + }); - const edges = graph.edges.map((e) => { - return InitEdgeParser(e); - }); + // 获取 yaml 初始化 flow + initFlow({ + nodes: [...nodes], + edges: [...edges], + }); + return; + }) + .catch(() => { + initFlow({ + nodes: [], + edges: [], + }); + }); + // const mockGraph = localStorage.getItem('magent_flow_testdata'); + // if (!mockGraph) { + // return; + // } + // const graph = yaml.load(mockGraph) as Graph; + // const nodes = graph.nodes.map((n) => { + // return InitNodeParser(n); + // }); - // 获取 yaml 初始化 flow - initFlow({ - nodes: [...nodes], - edges: [...edges], - }); - console.log('🚀 ~ AgentConfigViewComponent ~ initFlow:'); - }, [initFlow]); + // const edges = graph.edges.map((e) => { + // return InitEdgeParser(e); + // }); + + // // 获取 yaml 初始化 flow + // initFlow({ + // nodes: [...nodes], + // edges: [...edges], + // }); + // console.log('🚀 ~ AgentConfigViewComponent ~ initFlow:'); + }, [initFlow, instance]); return (
@@ -271,10 +310,15 @@ export interface AgentFlowViewOption { @transient() @view(viewId) export class AgentFlowView extends BaseView { + @inject(RequestHelper) request: RequestHelper; agentId: string; override view = AgentFlowComponent; @prop() agent: AgentModel; + + @prop() workflowId: string; + @prop() workflow: WorkflowMeta; + protected agentManager: AgentManager; constructor( @inject(ViewOption) option: AgentFlowViewOption, @@ -307,4 +351,36 @@ export class AgentFlowView extends BaseView { } return undefined; }; + + protected getWorkflowInfo = async (workflowId: string) => { + const res = await this.request.get( + `/api/v1/workflows/${workflowId}`, + {}, + ); + if (res.status === 200) { + this.workflow = res.data; + } + return this.workflow; + }; + + getGraphInfo = async () => { + await this.agent.ready; + const planner = this.agent.planner as WorkflowPlannerMeta; + const workflowId = planner.workflow_id; + this.workflowId = workflowId; + return await this.getWorkflowInfo(workflowId); + }; + + saveGraph = async (graph: Graph) => { + await this.agent.ready; + if (!this.workflowId || !this.workflow) { + return; + } + this.workflow.graph = graph; + const res = await this.request.put( + `/api/v1/workflows/${this.workflowId}`, + this.workflow, + ); + return res; + }; } diff --git a/web-apps/ui/src/views/agent-flow/flow-utils.ts b/web-apps/ui/src/views/agent-flow/flow-utils.ts index 6b8007a..8c47f39 100644 --- a/web-apps/ui/src/views/agent-flow/flow-utils.ts +++ b/web-apps/ui/src/views/agent-flow/flow-utils.ts @@ -12,7 +12,7 @@ export const OutputNodeParser = (node: NodeType) => { export const OutputEdgeParser = (edge: Edge) => { return { - id: edge.id, + id: edge.id.toString(), target_handler: edge.targetHandle, source_handler: edge.sourceHandle, source_node_id: edge.source, @@ -24,9 +24,9 @@ export const InitNodeParser = (node: NodeType) => { node['config'] = node['data']; delete node['data']; const obj: NodeType = { - id: node.id, + id: node.id.toString(), type: node.type, - position: node.position, + position: node.position || { x: 0, y: 0 }, data: { ...node }, }; return obj; @@ -37,8 +37,8 @@ export const InitEdgeParser = (edge: Edge) => { id: edge.id, targetHandle: edge.target_handler, sourceHandle: edge.source_handler, - source: edge.source_node_id, - target: edge.target_node_id, + source: edge.source_node_id.toString(), + target: edge.target_node_id.toString(), }; return obj; }; diff --git a/web-apps/ui/src/views/agent-flow/toolbar.tsx b/web-apps/ui/src/views/agent-flow/toolbar.tsx index d0ffba0..491d218 100644 --- a/web-apps/ui/src/views/agent-flow/toolbar.tsx +++ b/web-apps/ui/src/views/agent-flow/toolbar.tsx @@ -35,7 +35,7 @@ export const Toolbar = (props: { classname?: string; style?: React.CSSProperties + } + > + setToolModalOpen(false)} + data={{ + dataProvider: { + tool: [ + { + id: toolParam.find((p) => p.name === 'id')?.value?.content as string, + } as any, + ], + }, + rowSelectionType: 'radio', + onChange: (val) => { + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + name: val[0].nickname, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + tool_param: [ + { + name: 'id', + type: 'string', + value: { + content: val[0].id, + }, + }, + ], + input_param: val[0].parameters.map((p) => { + return { + name: p, + type: 'string', + value: { + type: 'reference', + }, + }; + }), + }, + }, + }, + })); + + setToolModalOpen(false); + }, + }} + modalItem={ToolsModal} + /> +
+ {data.config?.inputs?.input_param && ( + { + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + input_param: [...values], + }, + }, + }, + })); + }} + /> + )} + + + {(data.config?.outputs || []).map((output) => ( + + ))} + + } + /> +
+ + ); +}; diff --git a/web-packages/magent-flow/src/components/AIBasic/index.ts b/web-packages/magent-flow/src/components/AIBasic/index.ts new file mode 100644 index 0000000..8a85c7c --- /dev/null +++ b/web-packages/magent-flow/src/components/AIBasic/index.ts @@ -0,0 +1,5 @@ +export * from './CascaderInNode/index.js'; +export * from './CollapseWrapper/index.js'; +export * from './OutputVariableTree/OutputVariable/index.js'; +export * from './PromptEditor/index.js'; +export * from './SelectInNode/index.js'; diff --git a/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx index bdf3f78..3a317c0 100644 --- a/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx +++ b/web-packages/magent-flow/src/components/FlowWithPanel/index.tsx @@ -1,4 +1,3 @@ -import { EventEmitterContextProvider } from '@flow/context/event-emitter.js'; import type { NodeDataType } from '@flow/interfaces/flow.js'; import { NodeTypeEnum } from '@flow/interfaces/flow.js'; import yaml from 'js-yaml'; @@ -154,7 +153,6 @@ const templateNodeYaml = ` tool_param: - type: string name: id - value: google_search input_param: - type: string name: input diff --git a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx index 54807ae..176c7c4 100644 --- a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx +++ b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx @@ -1,7 +1,6 @@ import type { NodeDataType } from '@flow/interfaces/flow.js'; import { classNames } from '@flow/utils/index.js'; import { Handle, Position } from '@xyflow/react'; -import { Space } from 'antd'; import React from 'react'; type Props = { @@ -20,6 +19,9 @@ export const NodeWrapper = (props: { id: string; style: Record; }[]; + icon?: string; + name?: string | React.ReactNode; + extra?: React.ReactNode; }) => { const { nodeProps, @@ -27,8 +29,11 @@ export const NodeWrapper = (props: { leftHandler = true, rightHandler = true, rightHandlerConfig, + icon, + name, + extra, } = props; - const { name, description, icon } = nodeProps.data; + const { name: defautName, description, icon: defautIcon } = nodeProps.data; return (
{/* */}
- - {icon && } -
{name}
-
+
+ {(defautIcon || icon) && ( + + )} +
{name ?? defautName}
+
+ {extra}
{leftHandler && ( Date: Thu, 29 Aug 2024 20:57:02 +0800 Subject: [PATCH 32/78] feat: support agent use in flow --- web-apps/ui/src/modules/agent/agent-market.ts | 7 +- .../views/agent-flow/flow-with-tabs/index.tsx | 14 +- .../ui/src/views/agent-flow/nodes/agent.tsx | 190 ++++++++++++++++++ .../ui/src/views/agent-flow/nodes/tool.tsx | 14 +- .../agent-flow/nodes/transfer-button.tsx | 21 ++ .../components/AIBasic/PromptEditor/index.tsx | 4 +- .../src/components/Node/AgentNode/index.tsx | 7 +- .../src/components/Node/EndNode/index.tsx | 2 +- .../src/components/Node/LLMNode/index.tsx | 11 +- .../src/components/Node/NodeWrapper/index.tsx | 18 +- 10 files changed, 249 insertions(+), 39 deletions(-) create mode 100644 web-apps/ui/src/views/agent-flow/nodes/agent.tsx create mode 100644 web-apps/ui/src/views/agent-flow/nodes/transfer-button.tsx diff --git a/web-apps/ui/src/modules/agent/agent-market.ts b/web-apps/ui/src/modules/agent/agent-market.ts index f8431f8..3b1ee3c 100644 --- a/web-apps/ui/src/modules/agent/agent-market.ts +++ b/web-apps/ui/src/modules/agent/agent-market.ts @@ -5,7 +5,7 @@ import type { AgentModel } from './agent-model.js'; @singleton() export class AgentMarket { - @inject(AgentManager) agentManager: AgentManager; + agentManager: AgentManager; @prop() list: AgentModel[] = []; @@ -13,6 +13,11 @@ export class AgentMarket { @prop() loading = false; + constructor(@inject(AgentManager) agentManager: AgentManager) { + this.agentManager = agentManager; + this.update(); + } + async update() { this.loading = true; const options = await this.agentManager.getAll(); diff --git a/web-apps/ui/src/views/agent-flow/flow-with-tabs/index.tsx b/web-apps/ui/src/views/agent-flow/flow-with-tabs/index.tsx index 3d83de7..696c68a 100644 --- a/web-apps/ui/src/views/agent-flow/flow-with-tabs/index.tsx +++ b/web-apps/ui/src/views/agent-flow/flow-with-tabs/index.tsx @@ -6,7 +6,6 @@ import { KnowledgeNode, LLMNode, IfElseNode, - AgentNode, NodesPanel, Flow, } from '@difizen/magent-flow'; @@ -20,6 +19,7 @@ import knowledgeIcon from '../icons/knowledge.svg'; import llmIcon from '../icons/llm.svg'; import startIcon from '../icons/start.svg'; import toolIcon from '../icons/tool.svg'; +import { AgentNode } from '../nodes/agent.js'; import { ToolNode } from '../nodes/tool.js'; export const nodeIconMap = { @@ -57,7 +57,6 @@ const templateNodeYaml = ` value: type: reference prompt: - name: response type: string description: 输出内容 value: @@ -158,9 +157,14 @@ const templateNodeYaml = ` data: inputs: agent_param: - - type: string - name: id - value: demo_rag_agent + - name: id + type: string + - name: prompt + type: string + value: + type: value + content: | + 需要回答的问题是: {{input}} input_param: - type: string name: input diff --git a/web-apps/ui/src/views/agent-flow/nodes/agent.tsx b/web-apps/ui/src/views/agent-flow/nodes/agent.tsx new file mode 100644 index 0000000..8f8959b --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/nodes/agent.tsx @@ -0,0 +1,190 @@ +import type { BasicSchema, NodeDataType } from '@difizen/magent-flow'; +import { + CollapseWrapper, + PromptEditor, + NodeWrapper, + ReferenceForm, + useFlowStore, + OutputVariable, +} from '@difizen/magent-flow'; +import { useInject } from '@difizen/mana-app'; +import { Card, Modal } from 'antd'; +import { useState } from 'react'; + +import { AgentIcon } from '@/modules/agent/agent-icon.js'; +import { AgentMarket } from '@/modules/agent/agent-market.js'; + +import { TransferButton } from './transfer-button.js'; + +type Props = { + data: NodeDataType; + selected: boolean; + xPos: number; + yPos: number; +}; + +export const AgentNode = (props: Props) => { + const { data } = props; + + const [agentModalOpen, setAgentModalOpen] = useState(false); + const { findUpstreamNodes, setNode } = useFlowStore(); + const upstreamNodes = findUpstreamNodes(data.id.toString()); + const agentMarket = useInject(AgentMarket); + const agentParam = data.config?.inputs?.agent_param as BasicSchema[]; + + const agentList = agentMarket?.list.map((item) => item.toMeta()); + + const agenyMeta = agentList.find( + (agent) => agent.id === agentParam.find((a) => a.name === 'id')?.value?.content, + ); + + return ( + setAgentModalOpen(true)}> + 选择智能体 + + } + > + setAgentModalOpen(false)} + footer={null} + > + {agentList.map((item) => ( + { + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + name: item.nickname, + description: item.description, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + agent_param: [ + ...old.data.config.inputs.agent_param.filter( + (p: BasicSchema) => p.name !== 'id', + ), + { + name: 'id', + type: 'string', + value: { type: 'value', content: item.id }, + }, + ], + }, + }, + }, + })); + setAgentModalOpen(false); + }} + > + + + + } + title={item.nickname} + description={{item.description}} + /> + + ))} + +
+ { + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + input_param: [...values], + }, + }, + }, + })); + }} + /> + + item.name === 'prompt')?.value + ?.content as string) || '' + } + placeholder="请输入 Prompt" + onChange={(values: string) => { + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + config: { + ...(old.data.config as Record), + inputs: { + ...old.data.config.inputs, + agent_param: [ + ...agentParam.filter((p) => p.name !== 'prompt'), + { + name: 'prompt', + type: 'string', + value: { + type: 'value', + content: values, + }, + }, + ], + }, + }, + }, + })); + }} + variableBlock={{ + show: true, + variables: data.config?.inputs?.input_param.map((input) => { + return { + name: input.name, + value: input.name, + }; + }), + }} + /> +
+ } + /> + + {(data.config?.outputs || []).map((output) => ( + + ))} + + } + /> +
+ + ); +}; diff --git a/web-apps/ui/src/views/agent-flow/nodes/tool.tsx b/web-apps/ui/src/views/agent-flow/nodes/tool.tsx index 8f3f5d8..4007ca6 100644 --- a/web-apps/ui/src/views/agent-flow/nodes/tool.tsx +++ b/web-apps/ui/src/views/agent-flow/nodes/tool.tsx @@ -7,7 +7,6 @@ import { OutputVariable, } from '@difizen/magent-flow'; import { useInject } from '@difizen/mana-app'; -import { Button } from 'antd'; import { useState } from 'react'; import { ToolSpace } from '@/modules/tool/tool-space.js'; @@ -16,7 +15,7 @@ import { ToolsModalComponent, } from '@/views/agent-config/tools-modal/modal.js'; -import transferIcon from '../icons/transfer.svg'; +import { TransferButton } from './transfer-button.js'; type Props = { data: NodeDataType; @@ -41,16 +40,8 @@ export const ToolNode = (props: Props) => { } - onClick={() => setToolModalOpen(true)} - > - 选择工具 - + setToolModalOpen(true)}>选择工具 } > { data: { ...old.data, name: val[0].nickname, + description: val[0].description, config: { ...(old.data.config as Record), inputs: { diff --git a/web-apps/ui/src/views/agent-flow/nodes/transfer-button.tsx b/web-apps/ui/src/views/agent-flow/nodes/transfer-button.tsx new file mode 100644 index 0000000..4abbfe4 --- /dev/null +++ b/web-apps/ui/src/views/agent-flow/nodes/transfer-button.tsx @@ -0,0 +1,21 @@ +import { Button } from 'antd'; + +import transferIcon from '../icons/transfer.svg'; + +export const TransferButton = (props: { + icon?: string; + onClick: () => void; + children?: React.ReactNode; +}) => { + const { icon = transferIcon, onClick, children } = props; + return ( + + ); +}; diff --git a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx index 8c8061c..a3bbed7 100644 --- a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx @@ -35,7 +35,7 @@ export type PromptEditorProps = { externalToolBlock?: ExternalToolBlockType; }; -const PromptEditor: FC = ({ +export const PromptEditor: FC = ({ instanceId, compact, className, @@ -126,5 +126,3 @@ const PromptEditor: FC = ({ ); }; - -export default PromptEditor; diff --git a/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx b/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx index 88cca1b..a30874b 100644 --- a/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx +++ b/web-packages/magent-flow/src/components/Node/AgentNode/index.tsx @@ -1,8 +1,7 @@ import { CollapseWrapper } from '@flow/components/AIBasic/CollapseWrapper/index.js'; import { OutputVariable } from '@flow/components/AIBasic/OutputVariableTree/OutputVariable/index.js'; -import PromptEditor from '@flow/components/AIBasic/PromptEditor/index.js'; import { ReferenceForm } from '@flow/components/ReferenceForm/index.js'; -import type { BasicSchema, NodeDataType } from '@flow/interfaces/flow.js'; +import type { NodeDataType } from '@flow/interfaces/flow.js'; import { useFlowStore } from '@flow/stores/useFlowStore.js'; import { NodeWrapper } from '../NodeWrapper/index.js'; @@ -43,7 +42,7 @@ export const AgentNode = (props: Props) => { })); }} /> - { />
} - /> + /> */} { const upstreamNode = findUpstreamNodes(data.id.toString()); - const llm_param = data.config?.inputs?.llm_param as BasicSchema[]; + const llmParam = data.config?.inputs?.llm_param as BasicSchema[]; return ( @@ -38,7 +37,7 @@ export const LLMNode = (props: Props) => { label={'模型配置'} content={ ModelSelector !== null ? ( - + ) : (
{
item.name === 'prompt')?.value + (llmParam.find((item) => item.name === 'prompt')?.value ?.content as string) || '' } placeholder="请输入 Prompt" @@ -112,7 +111,7 @@ export const LLMNode = (props: Props) => { inputs: { ...old.data.config.inputs, llm_param: [ - ...llm_param, + ...llmParam.filter((p) => p.name !== 'prompt'), { name: 'prompt', type: 'string', diff --git a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx index 176c7c4..2712335 100644 --- a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx +++ b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx @@ -33,22 +33,22 @@ export const NodeWrapper = (props: { name, extra, } = props; - const { name: defautName, description, icon: defautIcon } = nodeProps.data; + const { name: defaultName, description, icon: defaultIcon } = nodeProps.data; return (
{/* */}
- {(defautIcon || icon) && ( - + {(defaultIcon || icon) && ( + )} -
{name ?? defautName}
+
{name ?? defaultName}
{extra}
@@ -86,9 +86,11 @@ export const NodeWrapper = (props: { /> ))} -
-
{description}
-
+ {description && ( +
+
{description}
+
+ )}
{children}
); From 870ed9e0300b657ea7578c74bef1d04f1ce07771 Mon Sep 17 00:00:00 2001 From: "xujianfeng.xjf" Date: Thu, 29 Aug 2024 19:42:53 +0800 Subject: [PATCH 33/78] feat: support tooluse in flow --- web-apps/ui/src/views/agent-config/view.tsx | 4 ++-- web-apps/ui/src/views/agent-flow/flow-utils.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web-apps/ui/src/views/agent-config/view.tsx b/web-apps/ui/src/views/agent-config/view.tsx index f7248f0..c4895f1 100644 --- a/web-apps/ui/src/views/agent-config/view.tsx +++ b/web-apps/ui/src/views/agent-config/view.tsx @@ -19,7 +19,7 @@ import { KnowledgeIcon } from '@/modules/knowledge/knowledge-icon.js'; import type { KnowledgeModelOption } from '@/modules/knowledge/protocol.js'; import { ModelSelector } from '@/modules/model/model-selector/index.js'; import { ToolIcon } from '@/modules/tool/icon/index.js'; -import type { ToolModelOption } from '@/modules/tool/protocol.js'; +import type { ToolMeta } from '@/modules/tool/protocol.js'; import { CharacterSetting } from './components/character-setting/index.js'; import { ConfigList } from './components/config-selector/index.js'; @@ -70,7 +70,7 @@ const AgentConfigViewComponent = forwardRef( if (instance.agent) { modalService.openModal(ToolsModal, { dataProvider: instance.agent, - onChange: (val: ToolModelOption[]) => { + onChange: (val: ToolMeta[]) => { instance.agent.tool = val; }, }); diff --git a/web-apps/ui/src/views/agent-flow/flow-utils.ts b/web-apps/ui/src/views/agent-flow/flow-utils.ts index c620e25..ae010d3 100644 --- a/web-apps/ui/src/views/agent-flow/flow-utils.ts +++ b/web-apps/ui/src/views/agent-flow/flow-utils.ts @@ -1,4 +1,4 @@ -import type { NodeType, Edge, NodeDataType } from '@difizen/magent-flow'; +import type { NodeType, Edge } from '@difizen/magent-flow'; import { nodeIconMap } from './flow-with-tabs/index.js'; @@ -19,7 +19,7 @@ export const OutputEdgeParser = (edge: Edge) => { source_handler: edge.sourceHandle, source_node_id: edge.source, target_node_id: edge.target, - } as Edge; + } as any; }; export const InitNodeParser = (node: NodeType) => { @@ -40,7 +40,7 @@ export const InitNodeParser = (node: NodeType) => { return obj; }; -export const InitEdgeParser = (edge: Edge) => { +export const InitEdgeParser = (edge: any) => { const obj: Edge = { id: edge.id, targetHandle: edge.target_handler, From 1152cacda705722073c5630c4db9a6d94f77c892 Mon Sep 17 00:00:00 2001 From: "xujianfeng.xjf" Date: Fri, 30 Aug 2024 10:58:19 +0800 Subject: [PATCH 34/78] fix: handler type --- .../magent-flow/src/components/Node/NodeWrapper/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx index 2712335..7edab5f 100644 --- a/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx +++ b/web-packages/magent-flow/src/components/Node/NodeWrapper/index.tsx @@ -54,7 +54,7 @@ export const NodeWrapper = (props: {
{leftHandler && ( ) : ( Date: Fri, 30 Aug 2024 11:26:52 +0800 Subject: [PATCH 35/78] fix(ui): tool creation btn --- web-apps/ui/src/views/knowledge/index.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web-apps/ui/src/views/knowledge/index.less b/web-apps/ui/src/views/knowledge/index.less index 3cecb69..0299074 100644 --- a/web-apps/ui/src/views/knowledge/index.less +++ b/web-apps/ui/src/views/knowledge/index.less @@ -56,11 +56,12 @@ &-creation { position: absolute; - top: -64px; + top: 0; right: 24px; height: 64px; display: flex; align-items: center; + z-index: 1; button { border: none; From 288710c601c4cd18ec16e0f17c949d4ad4fc4025 Mon Sep 17 00:00:00 2001 From: "xujianfeng.xjf" Date: Fri, 30 Aug 2024 11:41:29 +0800 Subject: [PATCH 36/78] fix: node inputparam reference --- web-packages/magent-flow/src/stores/useFlowStore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-packages/magent-flow/src/stores/useFlowStore.ts b/web-packages/magent-flow/src/stores/useFlowStore.ts index dd06f54..a8d4432 100644 --- a/web-packages/magent-flow/src/stores/useFlowStore.ts +++ b/web-packages/magent-flow/src/stores/useFlowStore.ts @@ -64,7 +64,7 @@ export const useFlowStore = create((set, get) => { adjList[node.id] = []; }); edges.forEach((edge) => { - adjList[edge.source].push(edge.target); + adjList[edge.target].push(edge.source); }); const visited = new Set(); From 0e018e67feea10b2fbaf7e586af9dace3fd10c25 Mon Sep 17 00:00:00 2001 From: "xujianfeng.xjf" Date: Fri, 30 Aug 2024 13:06:28 +0800 Subject: [PATCH 37/78] fix: ModelSelector models --- web-apps/ui/src/views/agent-flow/agent-flow-view.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx index 0f79342..774713f 100644 --- a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx +++ b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx @@ -87,7 +87,7 @@ const AgentFlowComponent = forwardRef( type: 'string', value: { type: 'value', - content: val.model_name, + content: val.model_name[0], }, }, ], From eadb193ec2f62dfcb48a8f2127ae8db28d46566b Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Fri, 30 Aug 2024 13:08:16 +0800 Subject: [PATCH 38/78] chore(ui): bugbatch --- .../magent-ui/src/magent_ui/routers/plugins/router.py | 2 +- web-apps/ui/src/modules/plugin/module.ts | 1 + web-apps/ui/src/modules/tool/protocol.ts | 5 +++++ web-apps/ui/src/modules/tool/tool-model.ts | 9 +++++++++ .../agent-config/components/character-setting/index.tsx | 8 ++++---- web-apps/ui/src/views/agents/modal/create.tsx | 2 +- web-apps/ui/src/views/plugins/view.tsx | 6 +++++- web-apps/ui/src/views/protal-layout/protocol.ts | 8 ++++---- 8 files changed, 30 insertions(+), 11 deletions(-) diff --git a/packages/magent-ui/src/magent_ui/routers/plugins/router.py b/packages/magent-ui/src/magent_ui/routers/plugins/router.py index f08ecf6..14e0efb 100644 --- a/packages/magent-ui/src/magent_ui/routers/plugins/router.py +++ b/packages/magent-ui/src/magent_ui/routers/plugins/router.py @@ -11,6 +11,6 @@ async def get_agents(): return PluginService.get_plugin_list() -@router.post("/plugins/openapi", response_model=List[PluginDTO]) +@router.post("/plugins/openapi", response_model=str) async def create_plugin_with_openapi(plugin: PluginDTO): return PluginService.create_plugin_with_openapi(plugin) diff --git a/web-apps/ui/src/modules/plugin/module.ts b/web-apps/ui/src/modules/plugin/module.ts index e79a087..2d624d8 100644 --- a/web-apps/ui/src/modules/plugin/module.ts +++ b/web-apps/ui/src/modules/plugin/module.ts @@ -8,6 +8,7 @@ import { PluginFactory } from './protocol.js'; export const PluginModule = ManaModule.create().register( PluginModel, + OpenAPIPluginModel, PluginManager, { diff --git a/web-apps/ui/src/modules/tool/protocol.ts b/web-apps/ui/src/modules/tool/protocol.ts index 61adc74..e8d03f6 100644 --- a/web-apps/ui/src/modules/tool/protocol.ts +++ b/web-apps/ui/src/modules/tool/protocol.ts @@ -45,6 +45,11 @@ export interface ToolMeta { avatar: string; description: string; parameters: string[]; + openapi_schema?: string; +} + +export interface OpenAPIToolMeta extends ToolMeta { + openapi_schema: string; } export const ToolModelOption = Syringe.defineToken('ToolModelOption', { diff --git a/web-apps/ui/src/modules/tool/tool-model.ts b/web-apps/ui/src/modules/tool/tool-model.ts index faa4561..321fad2 100644 --- a/web-apps/ui/src/modules/tool/tool-model.ts +++ b/web-apps/ui/src/modules/tool/tool-model.ts @@ -18,13 +18,19 @@ export class ToolModel extends AsyncModel { @prop() nickname: string; + @prop() avatar: string; + @prop() description: string; + @prop() parameters: string[] = []; + @prop() + openapi_schema?: string; + protected draftDeferred = new Deferred(); get draftReady() { @@ -69,6 +75,9 @@ export class ToolModel extends AsyncModel { if (option.parameters.length > 0) { this.parameters = option.parameters; } + if (option.openapi_schema) { + this.openapi_schema = option.openapi_schema; + } if (ToolModelType.isFullOption(option)) { super.fromMeta(option); } diff --git a/web-apps/ui/src/views/agent-config/components/character-setting/index.tsx b/web-apps/ui/src/views/agent-config/components/character-setting/index.tsx index 9c9612a..f00c672 100644 --- a/web-apps/ui/src/views/agent-config/components/character-setting/index.tsx +++ b/web-apps/ui/src/views/agent-config/components/character-setting/index.tsx @@ -118,16 +118,16 @@ export const CharacterSetting = memo(function CharacterSetting() { useEffect(() => { const keys = []; - if (prompt?.introduction) { + if (prompt?.introduction !== undefined) { keys.push('introduction'); } - if (prompt?.target) { + if (prompt?.target !== undefined) { keys.push('target'); } - if (prompt?.instruction) { + if (prompt?.instruction !== undefined) { keys.push('instruction'); } - if (agent.openingSpeech) { + if (agent.openingSpeech !== undefined) { keys.push('openingSpeech'); } setActiveKey(keys); diff --git a/web-apps/ui/src/views/agents/modal/create.tsx b/web-apps/ui/src/views/agents/modal/create.tsx index 2ed8537..8fca8b2 100644 --- a/web-apps/ui/src/views/agents/modal/create.tsx +++ b/web-apps/ui/src/views/agents/modal/create.tsx @@ -120,7 +120,7 @@ export const AgentModalComponent = (props: ModalItemProps) => { nickname: values.nickname, avatar: values.avatar, description: values.description, - prompt: { instruction: '', introduction: '', target: '' }, + prompt: { instruction: ' ', introduction: ' ', target: ' ' }, planner: { id: values.plannerId, nickname: '' }, llm: llmManager.default, }; diff --git a/web-apps/ui/src/views/plugins/view.tsx b/web-apps/ui/src/views/plugins/view.tsx index 9c6d944..306eaa8 100644 --- a/web-apps/ui/src/views/plugins/view.tsx +++ b/web-apps/ui/src/views/plugins/view.tsx @@ -66,7 +66,11 @@ const PluginsViewComponent = forwardRef( item.id)} + tags={item.toolset.map((item) => + item.openapi_schema + ? `${item.openapi_schema.method}: ${item.openapi_schema.path}` + : item.nickname, + )} maxWidth={400} > diff --git a/web-apps/ui/src/views/protal-layout/protocol.ts b/web-apps/ui/src/views/protal-layout/protocol.ts index 738964b..68d5588 100644 --- a/web-apps/ui/src/views/protal-layout/protocol.ts +++ b/web-apps/ui/src/views/protal-layout/protocol.ts @@ -8,10 +8,10 @@ export const portals: Portal[] = [ path: 'agents', label: '智能体', }, - { - path: 'tools', - label: '工具', - }, + // { + // path: 'tools', + // label: '工具', + // }, { path: 'plugins', label: '插件', From 9ca5a07a964bdb3972a218c2e0ed9d0001b7a650 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Fri, 30 Aug 2024 13:55:23 +0800 Subject: [PATCH 39/78] fix(ui): tool & knowledge --- web-apps/ui/src/modules/tool/protocol.ts | 4 ++-- web-apps/ui/src/modules/tool/tool-model.ts | 2 +- .../src/views/knowledge/create-modal/modal.tsx | 4 ++-- web-apps/ui/src/views/knowledge/protocol.ts | 1 + web-apps/ui/src/views/knowledge/view.tsx | 16 ++++++---------- web-apps/ui/src/views/plugins/view.tsx | 4 ++-- 6 files changed, 14 insertions(+), 17 deletions(-) diff --git a/web-apps/ui/src/modules/tool/protocol.ts b/web-apps/ui/src/modules/tool/protocol.ts index e8d03f6..ef072e6 100644 --- a/web-apps/ui/src/modules/tool/protocol.ts +++ b/web-apps/ui/src/modules/tool/protocol.ts @@ -45,11 +45,11 @@ export interface ToolMeta { avatar: string; description: string; parameters: string[]; - openapi_schema?: string; + openapi_schema?: Record; } export interface OpenAPIToolMeta extends ToolMeta { - openapi_schema: string; + openapi_schema: Record; } export const ToolModelOption = Syringe.defineToken('ToolModelOption', { diff --git a/web-apps/ui/src/modules/tool/tool-model.ts b/web-apps/ui/src/modules/tool/tool-model.ts index 321fad2..1c648f2 100644 --- a/web-apps/ui/src/modules/tool/tool-model.ts +++ b/web-apps/ui/src/modules/tool/tool-model.ts @@ -29,7 +29,7 @@ export class ToolModel extends AsyncModel { parameters: string[] = []; @prop() - openapi_schema?: string; + openapi_schema?: Record; protected draftDeferred = new Deferred(); diff --git a/web-apps/ui/src/views/knowledge/create-modal/modal.tsx b/web-apps/ui/src/views/knowledge/create-modal/modal.tsx index 2bc4613..2fb2c56 100644 --- a/web-apps/ui/src/views/knowledge/create-modal/modal.tsx +++ b/web-apps/ui/src/views/knowledge/create-modal/modal.tsx @@ -8,7 +8,7 @@ import { RequestHelper } from '@/modules/axios-client/request.js'; import { KnowledgeManager } from '../../../modules/knowledge/knowledge-manager.js'; import { KnowledgeSpace } from '../../../modules/knowledge/knowledge-space.js'; -import { KnowledgeModalId } from '../protocol.js'; +import { KnowledgeEditModalId } from '../protocol.js'; import { KnowledgeView } from '../view.js'; import './index.less'; @@ -131,6 +131,6 @@ export const KnowledgeModalComponent = ( }; export const KnowledgeModal: ModalItem = { - id: KnowledgeModalId, + id: KnowledgeEditModalId, component: KnowledgeModalComponent, }; diff --git a/web-apps/ui/src/views/knowledge/protocol.ts b/web-apps/ui/src/views/knowledge/protocol.ts index e94e632..145e4d4 100644 --- a/web-apps/ui/src/views/knowledge/protocol.ts +++ b/web-apps/ui/src/views/knowledge/protocol.ts @@ -1 +1,2 @@ export const KnowledgeModalId = 'knowledge.modal'; +export const KnowledgeEditModalId = 'knowledge.edit.modal'; diff --git a/web-apps/ui/src/views/knowledge/view.tsx b/web-apps/ui/src/views/knowledge/view.tsx index a1010f3..f1acacf 100644 --- a/web-apps/ui/src/views/knowledge/view.tsx +++ b/web-apps/ui/src/views/knowledge/view.tsx @@ -10,18 +10,15 @@ import { view, } from '@difizen/mana-app'; import { Button, Col, List, message, Row, Space } from 'antd'; -import { forwardRef, useState } from 'react'; +import { forwardRef } from 'react'; +import { history } from 'umi'; import { KnowledgeIcon } from '@/modules/knowledge/knowledge-icon.js'; import { KnowledgeManager } from '@/modules/knowledge/knowledge-manager.js'; -import type { - KnowledgeModel, - KnowledgeModelOption, -} from '@/modules/knowledge/protocol.js'; +import type { KnowledgeModel } from '@/modules/knowledge/protocol.js'; +import { KnowledgeEditModalId } from './protocol.js'; import './index.less'; -import { KnowledgeModal } from './create-modal/modal.js'; -import { history } from 'umi'; const viewId = 'magent-knowledge'; export const slot = `${viewId}-slot`; @@ -29,7 +26,6 @@ export const slot = `${viewId}-slot`; const KnowledgeViewComponent = forwardRef( function ToolsViewComponent(props, ref) { const instance = useInject(ViewInstance); - const [selectedItems, setSelectedItems] = useState([]); const modalService = useInject(ModalService); @@ -72,7 +68,7 @@ const KnowledgeViewComponent = forwardRef( - modalService.openModal(KnowledgeModal, { + modalService.openModal(KnowledgeEditModalId, { type: 'edit', knowledge_id: item.id, }) @@ -108,7 +104,7 @@ const KnowledgeViewComponent = forwardRef(
+ ); + } + return ( +
{ + setHovered(true); + }} + onMouseLeave={() => { + setHovered(false); + }} + > + {hovered ? ( + + ) : ( + + )} +
+ ); +}; + +interface ToolSelectProps { + dataProvider: { tool: ToolMeta[] }; + onChange?: (tool: ToolMeta[]) => void; + expandAll?: boolean; +} +export const ToolsModalComponent = (props: ModalItemProps) => { + const plugins = useInject(PluginManager); + const { visible, close } = props; + const { dataProvider, onChange, expandAll } = props.data || {}; + + useMount(() => { + plugins.updatePublic(); + }); + + if (!dataProvider) { + return null; + } + + // const onSelectChange = (newSelectedRowKeys: React.Key[]) => { + // onChange?.( + // toolSpace.list + // .filter((item) => newSelectedRowKeys.includes(item.id)) + // .map((item) => item.toMeta()), + // ); + // }; + + const extraProps: any = {}; + if (expandAll && plugins.publicList.length > 0) { + extraProps['activeKey'] = plugins.publicList.map((item) => item.id.toString()); + } + + return ( + close()} + width={1080} + title="选择工具" + footer={null} + className={`${prefix}`} + > + <>} + {...extraProps} + // style={{ background: token.colorBgContainer }} + items={plugins.publicList.map((item) => { + return { + key: item.id.toString(), + // label: item.nickname, + label: ( +
+ +
+
+ +
+ + +
+
+
+
+ + item.openapi_schema && item.openapi_schema['method'] + ? `${item.openapi_schema['method']}: ${item.openapi_schema['path']}` + : item.nickname, + )} + maxWidth={400} + > +
+
+
+ ), + + children: item.toolset.map((tool) => ( + +
+
+ + +
+
+ +
+ {props.data && } +
+
+ )), + }; + })} + /> +
+ ); +}; + +export const ToolsModal: ModalItem = { + id: ToolsModalId, + component: ToolsModalComponent, +}; diff --git a/web-apps/ui/src/views/agent-config/module.ts b/web-apps/ui/src/views/agent-config/module.ts index 3606c8c..4715fe3 100644 --- a/web-apps/ui/src/views/agent-config/module.ts +++ b/web-apps/ui/src/views/agent-config/module.ts @@ -1,11 +1,9 @@ import { ManaModule } from '@difizen/mana-app'; import { KnowledgeModalContribution } from './knowledge-modal/index.js'; -import { ToolsModalContribution } from './tools-modal/index.js'; import { AgentConfigView } from './view.js'; export const AgentConfigViewModule = ManaModule.create().register( AgentConfigView, - ToolsModalContribution, KnowledgeModalContribution, ); diff --git a/web-apps/ui/src/views/agent-config/protocol.ts b/web-apps/ui/src/views/agent-config/protocol.ts index f4a01d0..e94e632 100644 --- a/web-apps/ui/src/views/agent-config/protocol.ts +++ b/web-apps/ui/src/views/agent-config/protocol.ts @@ -1,2 +1 @@ -export const ToolsModalId = 'tool.modal'; export const KnowledgeModalId = 'knowledge.modal'; diff --git a/web-apps/ui/src/views/agent-config/tools-modal/modal.tsx b/web-apps/ui/src/views/agent-config/tools-modal/modal.tsx deleted file mode 100644 index 6eeb362..0000000 --- a/web-apps/ui/src/views/agent-config/tools-modal/modal.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import type { ModalItem, ModalItemProps } from '@difizen/mana-app'; -import { useInject, useMount } from '@difizen/mana-app'; -import type { TableColumnsType } from 'antd'; -import { Modal, Table } from 'antd'; -import type { RowSelectionType, TableRowSelection } from 'antd/es/table/interface.js'; -import { useMemo } from 'react'; - -import { ToolIcon } from '@/modules/tool/icon/index.js'; -import type { ToolMeta } from '@/modules/tool/protocol.js'; -import { ToolSpace } from '@/modules/tool/tool-space.js'; - -import { ToolsModalId } from '../protocol.js'; - -export const ToolsModalComponent = ( - props: ModalItemProps<{ - dataProvider: { tool: ToolMeta[] }; - rowSelectionType?: RowSelectionType; - onChange: (tool: ToolMeta[]) => void; - }>, -) => { - const toolSpace = useInject(ToolSpace); - const { visible, close } = props; - const { dataProvider, onChange, rowSelectionType = 'checkbox' } = props.data || {}; - - const columns = useMemo(() => { - const c: TableColumnsType = [ - { - title: 'id', - dataIndex: 'id', - key: 'id', - }, - - { - title: 'avatar', - dataIndex: 'avatar', - key: 'avatar', - render(value, item) { - return ; - }, - }, - { - title: 'nickname', - dataIndex: 'nickname', - key: 'nickname', - }, - - { - title: 'description', - dataIndex: 'description', - key: 'description', - }, - ]; - return c; - }, []); - - useMount(() => { - toolSpace.update(); - }); - - if (!dataProvider) { - return null; - } - - const onSelectChange = (newSelectedRowKeys: React.Key[]) => { - onChange?.( - toolSpace.list - .filter((item) => newSelectedRowKeys.includes(item.id)) - .map((item) => item.toMeta()), - ); - }; - - const rowSelection: TableRowSelection = { - selectedRowKeys: (dataProvider.tool || []).map((item) => item.id), - onChange: onSelectChange, - type: rowSelectionType, - }; - - return ( - close()} - width={1080} - title="选择工具" - footer={null} - > - - loading={toolSpace.loading} - rowSelection={rowSelection} - dataSource={toolSpace.list} - columns={columns} - rowKey={'id'} - > - - ); -}; - -export const ToolsModal: ModalItem = { - id: ToolsModalId, - component: ToolsModalComponent, -}; diff --git a/web-apps/ui/src/views/agent-config/view.tsx b/web-apps/ui/src/views/agent-config/view.tsx index c4895f1..34990cb 100644 --- a/web-apps/ui/src/views/agent-config/view.tsx +++ b/web-apps/ui/src/views/agent-config/view.tsx @@ -20,11 +20,11 @@ import type { KnowledgeModelOption } from '@/modules/knowledge/protocol.js'; import { ModelSelector } from '@/modules/model/model-selector/index.js'; import { ToolIcon } from '@/modules/tool/icon/index.js'; import type { ToolMeta } from '@/modules/tool/protocol.js'; +import { ToolsModalId } from '@/modules/tool/protocol.js'; import { CharacterSetting } from './components/character-setting/index.js'; import { ConfigList } from './components/config-selector/index.js'; import { KnowledgeModal } from './knowledge-modal/modal.js'; -import { ToolsModal } from './tools-modal/modal.js'; import './index.less'; const viewId = 'magent-dev-config'; @@ -68,8 +68,9 @@ const AgentConfigViewComponent = forwardRef( }), onAdd: () => { if (instance.agent) { - modalService.openModal(ToolsModal, { + modalService.openModal(ToolsModalId, { dataProvider: instance.agent, + expandAll: true, onChange: (val: ToolMeta[]) => { instance.agent.tool = val; }, diff --git a/web-apps/ui/src/views/agent-flow/nodes/tool.tsx b/web-apps/ui/src/views/agent-flow/nodes/tool.tsx index 4007ca6..32b5a79 100644 --- a/web-apps/ui/src/views/agent-flow/nodes/tool.tsx +++ b/web-apps/ui/src/views/agent-flow/nodes/tool.tsx @@ -10,10 +10,7 @@ import { useInject } from '@difizen/mana-app'; import { useState } from 'react'; import { ToolSpace } from '@/modules/tool/tool-space.js'; -import { - ToolsModal, - ToolsModalComponent, -} from '@/views/agent-config/tools-modal/modal.js'; +import { ToolsModal, ToolsModalComponent } from '@/modules/tool/tools-modal/modal.js'; import { TransferButton } from './transfer-button.js'; @@ -48,6 +45,7 @@ export const ToolNode = (props: Props) => { visible={toolModalOpen} close={() => setToolModalOpen(false)} data={{ + expandAll: true, dataProvider: { tool: [ { diff --git a/web-apps/ui/src/views/plugins/view.tsx b/web-apps/ui/src/views/plugins/view.tsx index 3b237f3..4b0bf02 100644 --- a/web-apps/ui/src/views/plugins/view.tsx +++ b/web-apps/ui/src/views/plugins/view.tsx @@ -108,37 +108,6 @@ const PluginsViewComponent = forwardRef( }; })} /> - {/* ( -
- - - - } - title={item.nickname} - description={item.description} - /> - - - - - item.openapi_schema && item.openapi_schema['method'] - ? `${item.openapi_schema['method']}: ${item.openapi_schema['path']}` - : item.nickname, - )} - maxWidth={400} - > - - - -
- )} - /> */}
diff --git a/web-apps/ui/src/modules/base-layout/index.less b/web-apps/ui/src/modules/base-layout/index.less index cbc517c..2876748 100644 --- a/web-apps/ui/src/modules/base-layout/index.less +++ b/web-apps/ui/src/modules/base-layout/index.less @@ -17,6 +17,14 @@ body { padding: 0 12px; display: flex; align-items: center; + + .mana-flex { + .mana-flex-item { + height: 100%; + display: flex; + align-items: center; + } + } } .mana-header-middle { diff --git a/web-apps/ui/src/modules/base-layout/module.ts b/web-apps/ui/src/modules/base-layout/module.ts index 98e7b58..545c5b4 100644 --- a/web-apps/ui/src/modules/base-layout/module.ts +++ b/web-apps/ui/src/modules/base-layout/module.ts @@ -54,7 +54,7 @@ export const BaseLayoutModule = ManaModule.create().register( }, }), createViewPreference({ - slot: HeaderArea.middle, + slot: HeaderArea.left, view: MagentMainTitleView, autoCreate: true, }), diff --git a/web-apps/ui/src/modules/base-layout/protocol.ts b/web-apps/ui/src/modules/base-layout/protocol.ts index 42cd967..e05a790 100644 --- a/web-apps/ui/src/modules/base-layout/protocol.ts +++ b/web-apps/ui/src/modules/base-layout/protocol.ts @@ -4,6 +4,7 @@ import type { ReactNode } from 'react'; export interface NavigatablePage extends View { goBack?: () => void; pageTitle: () => ReactNode; + hideBrand?: boolean; } export const NavigatablePageType = { diff --git a/web-apps/ui/src/modules/base-layout/title/index.less b/web-apps/ui/src/modules/base-layout/title/index.less index 2a544ba..36de060 100644 --- a/web-apps/ui/src/modules/base-layout/title/index.less +++ b/web-apps/ui/src/modules/base-layout/title/index.less @@ -1,6 +1,5 @@ .magent-main-title { - font-size: 18px; padding: 0 4px; - opacity: 0.8; + // opacity: 0.8; text-transform: none; } diff --git a/web-apps/ui/src/views/agent-config/index.less b/web-apps/ui/src/views/agent-config/index.less index 1ef2612..951904c 100644 --- a/web-apps/ui/src/views/agent-config/index.less +++ b/web-apps/ui/src/views/agent-config/index.less @@ -12,10 +12,12 @@ border-bottom: 1px solid var(--mana-color-border); padding: 0 24px; height: 64px; + min-height: 64px; &-save { cursor: pointer; padding: 4px; + border: none; } } diff --git a/web-apps/ui/src/views/agent-config/view.tsx b/web-apps/ui/src/views/agent-config/view.tsx index 34990cb..c1c5d43 100644 --- a/web-apps/ui/src/views/agent-config/view.tsx +++ b/web-apps/ui/src/views/agent-config/view.tsx @@ -1,4 +1,4 @@ -import { SaveOutlined } from '@ant-design/icons'; +import { LoadingOutlined, SaveOutlined } from '@ant-design/icons'; import { BaseView, ViewInstance, @@ -10,7 +10,7 @@ import { transient, ModalService, } from '@difizen/mana-app'; -import { Flex } from 'antd'; +import { Button, Flex, message } from 'antd'; import { forwardRef } from 'react'; import { AgentManager } from '@/modules/agent/agent-manager.js'; @@ -33,15 +33,25 @@ const AgentConfigViewComponent = forwardRef( function AgentConfigViewComponent(props, ref) { const instance = useInject(ViewInstance); const modalService = useInject(ModalService); + const agent = instance.agent; return (

编排

- instance.agent.save()} - /> + onClick={() => + agent.save().then((saved) => { + if (saved) { + message.success('保存成功'); + } + return; + }) + } + icon={agent.saving ? : } + >
@@ -50,68 +60,61 @@ const AgentConfigViewComponent = forwardRef(
模型
- +
{ + options: agent.tool.map((item) => { return { ...item, icon: , }; }), onAdd: () => { - if (instance.agent) { + if (agent) { modalService.openModal(ToolsModalId, { - dataProvider: instance.agent, + dataProvider: agent, expandAll: true, onChange: (val: ToolMeta[]) => { - instance.agent.tool = val; + agent.tool = val; }, }); } }, onDelete: (item) => { - if (!instance.agent) { + if (!agent) { return; } - instance.agent.tool = instance.agent.tool.filter( - (i) => i.id !== item.id, - ); + agent.tool = agent.tool.filter((i) => i.id !== item.id); }, }, { key: 'knowledge', title: '知识', - options: (instance.agent.knowledge || []).map((item) => { + options: (agent.knowledge || []).map((item) => { return { ...item, icon: , }; }), onAdd: () => { - if (instance.agent) { + if (agent) { modalService.openModal(KnowledgeModal, { - dataProvider: instance.agent, + dataProvider: agent, onChange: (knowledges: KnowledgeModelOption[]) => { - instance.agent.knowledge = [...knowledges]; + agent.knowledge = [...knowledges]; }, }); } }, onDelete: (item) => { - if (!instance.agent || !instance.agent.knowledge) { + if (!agent || !agent.knowledge) { return; } - instance.agent.knowledge = instance.agent.knowledge.filter( - (i) => i.id !== item.id, - ); + agent.knowledge = agent.knowledge.filter((i) => i.id !== item.id); }, }, ]} diff --git a/web-apps/ui/src/views/agent-dev/chat-view.tsx b/web-apps/ui/src/views/agent-dev/chat-view.tsx index fdfc7b1..50eb6d3 100644 --- a/web-apps/ui/src/views/agent-dev/chat-view.tsx +++ b/web-apps/ui/src/views/agent-dev/chat-view.tsx @@ -13,10 +13,12 @@ import { forwardRef, useEffect } from 'react'; import { useMatch } from 'react-router-dom'; import { history } from 'umi'; +import { AgentIcon } from '@/modules/agent/agent-icon.js'; import { AgentManager } from '@/modules/agent/agent-manager.js'; import type { AgentModel } from '@/modules/agent/protocol.js'; import { PageView } from '@/modules/base-layout/page-view.js'; import type { SessionModel } from '@/modules/session/protocol.js'; + import { ChatView } from '../chat/view.js'; import { SessionsView } from '../sessions/view.js'; @@ -53,12 +55,18 @@ const AgentChatComponent = forwardRef( const Title = () => { const instance = useInject(ViewInstance); - return <>{instance.agent?.name}; + return ( +
+ + {instance.agent?.name} +
+ ); }; @singleton() @view(viewId) export class AgentView extends PageView { + hideBrand = true; protected _agentId?: string; get agentId(): string | undefined { diff --git a/web-apps/ui/src/views/agent-dev/index.less b/web-apps/ui/src/views/agent-dev/index.less index efe5dda..fb605b9 100644 --- a/web-apps/ui/src/views/agent-dev/index.less +++ b/web-apps/ui/src/views/agent-dev/index.less @@ -27,6 +27,7 @@ &-config { width: 55%; + border-radius: 8px; } &-chat-dev { @@ -112,3 +113,17 @@ margin-left: 6px; cursor: pointer; } + +.magent-agent-title { + height: 100%; + display: flex; + align-items: center; + font-size: 16px; + font-weight: 500; + + &-icon { + width: 42px; + height: 42px; + margin-right: 12px; + } +} From 58ebe59d9c5d2fe349b91bc63af8b18d249a111a Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 3 Sep 2024 01:50:27 +0800 Subject: [PATCH 53/78] fix(ui): spelling --- web-apps/ui/src/modules/app.module.ts | 2 +- .../ui/src/views/{protal-layout => portal-layout}/index.less | 0 web-apps/ui/src/views/{protal-layout => portal-layout}/index.ts | 0 .../ui/src/views/{protal-layout => portal-layout}/module.ts | 0 .../ui/src/views/{protal-layout => portal-layout}/protocol.ts | 0 web-apps/ui/src/views/{protal-layout => portal-layout}/view.tsx | 2 +- 6 files changed, 2 insertions(+), 2 deletions(-) rename web-apps/ui/src/views/{protal-layout => portal-layout}/index.less (100%) rename web-apps/ui/src/views/{protal-layout => portal-layout}/index.ts (100%) rename web-apps/ui/src/views/{protal-layout => portal-layout}/module.ts (100%) rename web-apps/ui/src/views/{protal-layout => portal-layout}/protocol.ts (100%) rename web-apps/ui/src/views/{protal-layout => portal-layout}/view.tsx (98%) diff --git a/web-apps/ui/src/modules/app.module.ts b/web-apps/ui/src/modules/app.module.ts index 8f97c12..81cc3a0 100644 --- a/web-apps/ui/src/modules/app.module.ts +++ b/web-apps/ui/src/modules/app.module.ts @@ -8,7 +8,7 @@ import { ChatViewModule } from '@/views/chat/module.js'; import { DebugModule } from '@/views/debug/module.js'; import { KnowledgePageModule } from '@/views/knowledge/module.js'; import { PluginPageModule } from '@/views/plugins/module.js'; -import { PortalsModule } from '@/views/protal-layout/module.js'; +import { PortalsModule } from '@/views/portal-layout/module.js'; import { SessionsViewModule } from '@/views/sessions/module.js'; import { ToolPageModule } from '@/views/tools/module.js'; diff --git a/web-apps/ui/src/views/protal-layout/index.less b/web-apps/ui/src/views/portal-layout/index.less similarity index 100% rename from web-apps/ui/src/views/protal-layout/index.less rename to web-apps/ui/src/views/portal-layout/index.less diff --git a/web-apps/ui/src/views/protal-layout/index.ts b/web-apps/ui/src/views/portal-layout/index.ts similarity index 100% rename from web-apps/ui/src/views/protal-layout/index.ts rename to web-apps/ui/src/views/portal-layout/index.ts diff --git a/web-apps/ui/src/views/protal-layout/module.ts b/web-apps/ui/src/views/portal-layout/module.ts similarity index 100% rename from web-apps/ui/src/views/protal-layout/module.ts rename to web-apps/ui/src/views/portal-layout/module.ts diff --git a/web-apps/ui/src/views/protal-layout/protocol.ts b/web-apps/ui/src/views/portal-layout/protocol.ts similarity index 100% rename from web-apps/ui/src/views/protal-layout/protocol.ts rename to web-apps/ui/src/views/portal-layout/protocol.ts diff --git a/web-apps/ui/src/views/protal-layout/view.tsx b/web-apps/ui/src/views/portal-layout/view.tsx similarity index 98% rename from web-apps/ui/src/views/protal-layout/view.tsx rename to web-apps/ui/src/views/portal-layout/view.tsx index 80e246f..a3bbeb2 100644 --- a/web-apps/ui/src/views/protal-layout/view.tsx +++ b/web-apps/ui/src/views/portal-layout/view.tsx @@ -13,7 +13,7 @@ import { useNavigate } from 'umi'; import { portals } from './protocol.js'; -import './index.less'; +import './index.less.js'; const viewId = 'magent-portal'; export const slot = `${viewId}-slot`; From 3d6f1f54d3f86aed83fef0271894a4c23430a5d5 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 3 Sep 2024 02:12:42 +0800 Subject: [PATCH 54/78] feat(ui): last modify time in title --- web-apps/ui/src/modules/agent/agent-model.ts | 8 ++++++++ web-apps/ui/src/modules/agent/protocol.ts | 1 + web-apps/ui/src/views/agent-config/view.tsx | 1 + web-apps/ui/src/views/agent-dev/chat-view.tsx | 19 +++++++++++++++++-- web-apps/ui/src/views/agent-dev/index.less | 14 ++++++++++++++ web-apps/ui/src/views/portal-layout/view.tsx | 2 +- 6 files changed, 42 insertions(+), 3 deletions(-) diff --git a/web-apps/ui/src/modules/agent/agent-model.ts b/web-apps/ui/src/modules/agent/agent-model.ts index f46a96c..2a0b9a4 100644 --- a/web-apps/ui/src/modules/agent/agent-model.ts +++ b/web-apps/ui/src/modules/agent/agent-model.ts @@ -1,4 +1,6 @@ import { inject, prop, transient } from '@difizen/mana-app'; +import type { Dayjs } from 'dayjs'; +import dayjs from 'dayjs'; import { AsyncModel } from '@/common/async-model.js'; @@ -77,6 +79,9 @@ export class AgentModel extends AsyncModel { @prop() knowledge?: KnowledgeModelOption[]; + @prop() + mtime?: Dayjs; + @prop() saving?: boolean; @@ -117,6 +122,9 @@ export class AgentModel extends AsyncModel { this.knowledge = option.knowledge; this.tool = option.tool ?? []; this.openingSpeech = option.opening_speech; + if (option.mtime) { + this.mtime = dayjs.unix(option.mtime); + } if (AgentModelType.isFullOption(option)) { super.fromMeta(option); diff --git a/web-apps/ui/src/modules/agent/protocol.ts b/web-apps/ui/src/modules/agent/protocol.ts index 73255ed..ef57562 100644 --- a/web-apps/ui/src/modules/agent/protocol.ts +++ b/web-apps/ui/src/modules/agent/protocol.ts @@ -72,6 +72,7 @@ export interface AgentModelOption { planner?: PlannerMeta; tool?: ToolMeta[]; knowledge?: any[]; + mtime?: number; } export const AgentModelOption = Syringe.defineToken('AgentBotOption', { diff --git a/web-apps/ui/src/views/agent-config/view.tsx b/web-apps/ui/src/views/agent-config/view.tsx index c1c5d43..8ebed79 100644 --- a/web-apps/ui/src/views/agent-config/view.tsx +++ b/web-apps/ui/src/views/agent-config/view.tsx @@ -47,6 +47,7 @@ const AgentConfigViewComponent = forwardRef( if (saved) { message.success('保存成功'); } + agent.fetchInfo(undefined, true); return; }) } diff --git a/web-apps/ui/src/views/agent-dev/chat-view.tsx b/web-apps/ui/src/views/agent-dev/chat-view.tsx index 50eb6d3..c82f372 100644 --- a/web-apps/ui/src/views/agent-dev/chat-view.tsx +++ b/web-apps/ui/src/views/agent-dev/chat-view.tsx @@ -23,6 +23,7 @@ import { ChatView } from '../chat/view.js'; import { SessionsView } from '../sessions/view.js'; import './index.less'; +import { FieldTimeOutlined } from '@ant-design/icons'; const viewId = 'magent-agent-chat'; export const slot = `${viewId}-slot`; @@ -55,10 +56,24 @@ const AgentChatComponent = forwardRef( const Title = () => { const instance = useInject(ViewInstance); + const agent = instance.agent; + let title =
{agent?.name}
; + if (agent?.mtime) { + title = ( +
+
{agent.name}
+ + + 最近更新: + {agent.mtime.format('YYYY-MM-DD HH:mm:ss')} + +
+ ); + } return (
- - {instance.agent?.name} + + {title}
); }; diff --git a/web-apps/ui/src/views/agent-dev/index.less b/web-apps/ui/src/views/agent-dev/index.less index fb605b9..6d842c5 100644 --- a/web-apps/ui/src/views/agent-dev/index.less +++ b/web-apps/ui/src/views/agent-dev/index.less @@ -126,4 +126,18 @@ height: 42px; margin-right: 12px; } + + &-text { + &-mtime { + font-size: 12px; + font-weight: 400; + padding: 4px 6px; + border-radius: 6px; + background: var(--mana-ant-color-bg-layout); + + .anticon { + margin-right: 4px; + } + } + } } diff --git a/web-apps/ui/src/views/portal-layout/view.tsx b/web-apps/ui/src/views/portal-layout/view.tsx index a3bbeb2..80e246f 100644 --- a/web-apps/ui/src/views/portal-layout/view.tsx +++ b/web-apps/ui/src/views/portal-layout/view.tsx @@ -13,7 +13,7 @@ import { useNavigate } from 'umi'; import { portals } from './protocol.js'; -import './index.less.js'; +import './index.less'; const viewId = 'magent-portal'; export const slot = `${viewId}-slot`; From ecffef6b545b06c99c0e5e255c0c031367c3befd Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 3 Sep 2024 02:39:15 +0800 Subject: [PATCH 55/78] feat(ui): github link --- .../src/modules/base-layout/github/index.less | 32 ++++++++++++ .../src/modules/base-layout/github/view.tsx | 49 ++++++++++++++++--- 2 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 web-apps/ui/src/modules/base-layout/github/index.less diff --git a/web-apps/ui/src/modules/base-layout/github/index.less b/web-apps/ui/src/modules/base-layout/github/index.less new file mode 100644 index 0000000..67f8541 --- /dev/null +++ b/web-apps/ui/src/modules/base-layout/github/index.less @@ -0,0 +1,32 @@ +.magent-github { + .ant-dropdown-menu { + .ant-dropdown-menu-item { + &:hover { + background: transparent; + } + + &:not(:last-child) { + border-bottom: 1px solid var(--mana-ant-color-border-secondary); + border-radius: 0; + } + } + } + + .magent-github-au { + width: 160px; + display: flex; + } + + .magent-github-magent { + width: 160px; + display: flex; + align-items: center; + padding: 0 10px; + font-size: 16px; + + svg { + margin-right: 8px; + height: 24px; + } + } +} diff --git a/web-apps/ui/src/modules/base-layout/github/view.tsx b/web-apps/ui/src/modules/base-layout/github/view.tsx index 40d549e..b9eb066 100644 --- a/web-apps/ui/src/modules/base-layout/github/view.tsx +++ b/web-apps/ui/src/modules/base-layout/github/view.tsx @@ -1,16 +1,54 @@ import { GithubFilled } from '@ant-design/icons'; -import { BaseView, singleton, useInject, view, ViewInstance } from '@difizen/mana-app'; -import { Button } from 'antd'; +import { BaseView, singleton, view } from '@difizen/mana-app'; +import type { MenuProps } from 'antd'; +import { Button, Dropdown } from 'antd'; import { forwardRef } from 'react'; +import { AULOGO, MagentLOGO } from '../brand/logo.js'; + +import './index.less'; + const GithubLinkComponent = forwardRef( function MagentBrandComponent(props, ref) { - const instance = useInject(ViewInstance); + const items: MenuProps['items'] = [ + { + key: '1', + label: ( + + + + ), + }, + { + key: '2', + label: ( + + + magent + + ), + }, + ]; return ( ); }, @@ -19,6 +57,5 @@ const GithubLinkComponent = forwardRef( @singleton() @view('github-link') export class GithubLinkView extends BaseView { - link = 'https://github.com/alipay/agentUniverse'; override view = GithubLinkComponent; } From 2d7bc5451995941d557510726c190952fae995b4 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 3 Sep 2024 12:02:42 +0800 Subject: [PATCH 56/78] feat(ui): move graph main operation to toolbar in header --- .../ui/src/modules/base-layout/index.less | 8 + web-apps/ui/src/modules/base-layout/module.ts | 13 ++ .../modules/base-layout/toolbar/index.less | 3 + .../src/modules/base-layout/toolbar/index.tsx | 26 ++++ .../src/views/agent-flow/agent-flow-view.tsx | 14 +- .../ui/src/views/agent-flow/flow-dev-view.tsx | 9 ++ web-apps/ui/src/views/agent-flow/index.less | 4 + web-apps/ui/src/views/agent-flow/module.ts | 2 + web-apps/ui/src/views/agent-flow/toolbar.tsx | 147 ++++++++++++------ 9 files changed, 163 insertions(+), 63 deletions(-) create mode 100644 web-apps/ui/src/modules/base-layout/toolbar/index.less create mode 100644 web-apps/ui/src/modules/base-layout/toolbar/index.tsx diff --git a/web-apps/ui/src/modules/base-layout/index.less b/web-apps/ui/src/modules/base-layout/index.less index 2876748..792c777 100644 --- a/web-apps/ui/src/modules/base-layout/index.less +++ b/web-apps/ui/src/modules/base-layout/index.less @@ -32,6 +32,14 @@ body { align-items: center; justify-content: center; } + + .mana-header-right { + .mana-toolbar { + .ant-btn { + border: none; + } + } + } } &-header { diff --git a/web-apps/ui/src/modules/base-layout/module.ts b/web-apps/ui/src/modules/base-layout/module.ts index 545c5b4..3eaef65 100644 --- a/web-apps/ui/src/modules/base-layout/module.ts +++ b/web-apps/ui/src/modules/base-layout/module.ts @@ -13,6 +13,7 @@ import { GithubLinkView } from './github/view.js'; import { MagentBaseLayoutSlots, MagentBaseLayoutView, slot } from './layout.js'; import { MainView } from './main-view.js'; import { MagentMainTitleView } from './title/view.js'; +import { MagentMainToolbarView } from './toolbar/index.js'; export const BaseLayoutModule = ManaModule.create().register( MainView, @@ -22,6 +23,7 @@ export const BaseLayoutModule = ManaModule.create().register( MagentBaseLayoutView, MagentBrandView, GithubLinkView, + MagentMainToolbarView, createSlotPreference({ slot: MagentBaseLayoutSlots.header, @@ -58,9 +60,20 @@ export const BaseLayoutModule = ManaModule.create().register( view: MagentMainTitleView, autoCreate: true, }), + createViewPreference({ + slot: HeaderArea.right, + view: MagentMainToolbarView, + autoCreate: true, + openOptions: { + order: 'b_toolbar', + }, + }), createViewPreference({ slot: HeaderArea.right, view: GithubLinkView, autoCreate: true, + openOptions: { + order: 'a_github', + }, }), ); diff --git a/web-apps/ui/src/modules/base-layout/toolbar/index.less b/web-apps/ui/src/modules/base-layout/toolbar/index.less new file mode 100644 index 0000000..353ff3b --- /dev/null +++ b/web-apps/ui/src/modules/base-layout/toolbar/index.less @@ -0,0 +1,3 @@ +.magent-main-toolbar { + margin-right: 16px; +} diff --git a/web-apps/ui/src/modules/base-layout/toolbar/index.tsx b/web-apps/ui/src/modules/base-layout/toolbar/index.tsx new file mode 100644 index 0000000..2130220 --- /dev/null +++ b/web-apps/ui/src/modules/base-layout/toolbar/index.tsx @@ -0,0 +1,26 @@ +import { BaseView, singleton, ToolbarRender, useInject, view } from '@difizen/mana-app'; +import { forwardRef } from 'react'; + +import { MainView } from '../main-view.js'; + +import './index.less'; + +const viewId = 'magent-main-toolbar'; + +const MagentMainToolbarComponent = forwardRef( + function MagentMainToolbarComponent(props, ref) { + const mainView = useInject(MainView); + + return ( +
+ +
+ ); + }, +); + +@singleton() +@view(viewId) +export class MagentMainToolbarView extends BaseView { + override view = MagentMainToolbarComponent; +} diff --git a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx index 774713f..dd8d327 100644 --- a/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx +++ b/web-apps/ui/src/views/agent-flow/agent-flow-view.tsx @@ -32,7 +32,6 @@ import { import { InitEdgeParser, InitNodeParser } from './flow-utils.js'; import { FlowWithTabs } from './flow-with-tabs/index.js'; -import { Toolbar } from './toolbar.js'; const viewId = 'magent-agent-flow'; @@ -263,18 +262,7 @@ const AgentFlowComponent = forwardRef( return (
- - } - /> + } />
); }, diff --git a/web-apps/ui/src/views/agent-flow/flow-dev-view.tsx b/web-apps/ui/src/views/agent-flow/flow-dev-view.tsx index 8cbc2d7..ec5d2b5 100644 --- a/web-apps/ui/src/views/agent-flow/flow-dev-view.tsx +++ b/web-apps/ui/src/views/agent-flow/flow-dev-view.tsx @@ -8,6 +8,7 @@ import { forwardRef, useEffect } from 'react'; import { useMatch } from 'react-router-dom'; import type { AgentConfigManager } from '@/modules/agent/agent-config-manager.js'; +import type { Graph } from '@/modules/workflow/protocol.js'; import { AgentView } from '../agent-dev/chat-view.js'; import { DebugDrawer } from '../debug/debug-drawer.js'; @@ -96,4 +97,12 @@ export class AgentFlowDevView extends AgentView { }); this.agentFlow = agentFlow; }; + + save = async (graph: Graph) => { + const res = await this.agentFlow?.saveGraph(graph); + if (res?.status === 200) { + return await this.agent?.save(); + } + return false; + }; } diff --git a/web-apps/ui/src/views/agent-flow/index.less b/web-apps/ui/src/views/agent-flow/index.less index ff122e1..4293c57 100644 --- a/web-apps/ui/src/views/agent-flow/index.less +++ b/web-apps/ui/src/views/agent-flow/index.less @@ -163,3 +163,7 @@ } } } + +.magent-agent-chat-btn-actived { + background: var(--mana-ant-color-bg-text-hover); +} diff --git a/web-apps/ui/src/views/agent-flow/module.ts b/web-apps/ui/src/views/agent-flow/module.ts index ddc6bba..774094e 100644 --- a/web-apps/ui/src/views/agent-flow/module.ts +++ b/web-apps/ui/src/views/agent-flow/module.ts @@ -5,12 +5,14 @@ import { AgentConfigViewModule } from '../agent-config/module.js'; import { AgentFlowView } from './agent-flow-view.js'; import { AgentFlowDevView, slot } from './flow-dev-view.js'; import { ReactFlowThemeContribution } from './react-flow-theme-contribution.js'; +import { AgentFlowMainToolbarContribution } from './toolbar.js'; export const AgentFlowModule = ManaModule.create() .register( AgentFlowView, AgentFlowDevView, ReactFlowThemeContribution, + AgentFlowMainToolbarContribution, createSlotPreference({ slot: slot, view: AgentFlowDevView, diff --git a/web-apps/ui/src/views/agent-flow/toolbar.tsx b/web-apps/ui/src/views/agent-flow/toolbar.tsx index 491d218..841fd9f 100644 --- a/web-apps/ui/src/views/agent-flow/toolbar.tsx +++ b/web-apps/ui/src/views/agent-flow/toolbar.tsx @@ -1,65 +1,112 @@ import { MessageOutlined, SaveOutlined } from '@ant-design/icons'; -import type { NodeType } from '@difizen/magent-flow'; +import type { Edge, NodeType } from '@difizen/magent-flow'; import { useFlowStore } from '@difizen/magent-flow'; -import { useInject } from '@difizen/mana-app'; +import type { CommandRegistry, ToolbarRegistry } from '@difizen/mana-app'; +import { + singleton, + ToolbarContribution, + useInject, + CommandContribution, +} from '@difizen/mana-app'; import { Button, message } from 'antd'; import classNames from 'classnames'; import yaml from 'js-yaml'; -import React from 'react'; + +import type { MainView } from '@/modules/base-layout/main-view.js'; import { AgentFlowDevView } from './flow-dev-view.js'; import { OutputEdgeParser, OutputNodeParser } from './flow-utils.js'; -export const Toolbar = (props: { classname?: string; style?: React.CSSProperties }) => { - const { classname, style } = props; - const { getFlow } = useFlowStore(); +export const RunButton = () => { const flowDevView = useInject(AgentFlowDevView); - return ( -
(flowDevView.hideChat = !flowDevView.hideChat)} + icon={} > - {flowDevView.hideChat && ( - - )} - + ); +}; +export const SaveButton = () => { + const flowDevView = useInject(AgentFlowDevView); + const { getFlow } = useFlowStore(); + return ( + -
+ const saved = await flowDevView.save(graph); + if (saved) { + message.success('保存成功'); + } + const graph_yaml = yaml.dump(graph); + localStorage.setItem('magent_flow_testdata', graph_yaml); + }} + > + 保存 + ); }; + +export const AgentFlowCommnds = { + chat: { + id: 'agent-flow-chat', + }, + save: { + id: 'agent-flow-save', + }, +}; +@singleton({ contrib: [CommandContribution, ToolbarContribution] }) +export class AgentFlowMainToolbarContribution + implements ToolbarContribution, CommandContribution +{ + protected isAgentFlowDev = (mainView: MainView) => { + return !!( + mainView && + mainView.active && + mainView.active instanceof AgentFlowDevView + ); + }; + registerCommands(commands: CommandRegistry) { + commands.registerCommand(AgentFlowCommnds['chat'], { + execute: () => { + // + }, + isVisible: this.isAgentFlowDev, + }); + commands.registerCommand(AgentFlowCommnds['save'], { + execute: () => { + // + }, + isVisible: this.isAgentFlowDev, + isEnabled: () => true, + }); + } + registerToolbarItems(registry: ToolbarRegistry): void { + registry.registerItem({ + id: `${AgentFlowCommnds['chat'].id}-toolbar-item`, + icon: RunButton, + command: AgentFlowCommnds['chat'].id, + }); + registry.registerItem({ + id: `${AgentFlowCommnds['save'].id}-toolbar-item`, + icon: SaveButton, + command: AgentFlowCommnds['save'].id, + }); + } +} From 6ee83d0a6ba3cf923bced9cb7fafbf12dead5147 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 3 Sep 2024 12:12:15 +0800 Subject: [PATCH 57/78] fix(ui): refetch agent info when graph saved --- web-apps/ui/src/views/agent-flow/toolbar.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/web-apps/ui/src/views/agent-flow/toolbar.tsx b/web-apps/ui/src/views/agent-flow/toolbar.tsx index 841fd9f..7c7d019 100644 --- a/web-apps/ui/src/views/agent-flow/toolbar.tsx +++ b/web-apps/ui/src/views/agent-flow/toolbar.tsx @@ -53,6 +53,7 @@ export const SaveButton = () => { const saved = await flowDevView.save(graph); if (saved) { message.success('保存成功'); + flowDevView.agent?.fetchInfo(undefined, true); } const graph_yaml = yaml.dump(graph); localStorage.setItem('magent_flow_testdata', graph_yaml); From b8d8fdf15273f474e05bcba76c35b9028754e848 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 3 Sep 2024 12:58:58 +0800 Subject: [PATCH 58/78] feat(ui): agents card --- web-apps/ui/package.json | 5 +++-- web-apps/ui/src/views/agents/index.less | 24 +++++++++++++++++++++ web-apps/ui/src/views/agents/view.tsx | 28 +++++++++++++++++-------- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/web-apps/ui/package.json b/web-apps/ui/package.json index c4a005e..602c95d 100644 --- a/web-apps/ui/package.json +++ b/web-apps/ui/package.json @@ -22,7 +22,6 @@ "deploy": "rimraf ../../packages/magent-ui/src/magent_ui/static && copyfiles -u 1 dist/* ../../packages/magent-ui/src/magent_ui/static/ && copyfiles -u 1 dist/**/* ../../packages/magent-ui/src/magent_ui/static/" }, "dependencies": { - "js-yaml": "^4.1.0", "@ant-design/icons": "^5.3.6", "@difizen/libro-jupyter": "^0.2.1", "@difizen/libro-lab": "^0.2.1", @@ -39,6 +38,7 @@ "copy-to-clipboard": "^3.3.3", "dayjs": "^1.11.10", "eventsource-parser": "^1.1.2", + "js-yaml": "^4.1.0", "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", "query-string": "^9.0.0", @@ -47,15 +47,16 @@ "react-zoom-pan-pinch": "^3.6.1", "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.0", + "timeago.js": "^4.0.2", "umi": "^4.1.1" }, "devDependencies": { - "@types/js-yaml": "^4.0.9", "@babel/plugin-proposal-decorators": "^7.23.7", "@babel/plugin-transform-class-properties": "^7.23.3", "@babel/plugin-transform-flow-strip-types": "^7.23.3", "@babel/plugin-transform-private-methods": "^7.23.3", "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@types/js-yaml": "^4.0.9", "@types/lodash.debounce": "^4.0.9", "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", diff --git a/web-apps/ui/src/views/agents/index.less b/web-apps/ui/src/views/agents/index.less index d052779..d253c78 100644 --- a/web-apps/ui/src/views/agents/index.less +++ b/web-apps/ui/src/views/agents/index.less @@ -15,6 +15,30 @@ .agent-card { width: 100%; margin-bottom: 16px; + + &-footer { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 16px; + } + + &-mtime { + font-size: 12px; + } + + &-actions { + button { + border: none; + color: var(--mana-ant-color-icon); + } + } + } + + .ant-card-actions { + li { + margin: 0; + } } } diff --git a/web-apps/ui/src/views/agents/view.tsx b/web-apps/ui/src/views/agents/view.tsx index ce359df..ba15a0f 100644 --- a/web-apps/ui/src/views/agents/view.tsx +++ b/web-apps/ui/src/views/agents/view.tsx @@ -11,14 +11,15 @@ import { } from '@difizen/mana-app'; import { Button, Card } from 'antd'; import { forwardRef } from 'react'; +import { format } from 'timeago.js'; import { history } from 'umi'; -import './index.less'; import { AgentIcon } from '@/modules/agent/agent-icon.js'; import { AgentMarket } from '@/modules/agent/agent-market.js'; import type { AgentModel } from '@/modules/agent/agent-model.js'; import { AgentCreateModal } from './modal/create.js'; +import './index.less'; const viewId = 'magent-agents'; export const slot = `${viewId}-slot`; @@ -40,14 +41,23 @@ const AgentsViewComponent = forwardRef( key={item.id} hoverable actions={[ - { - e.stopPropagation(); - instance.toDevPage(item); - }} - key="dev" - />, - , +
+
+ {item.mtime ? format(item.mtime.toDate(), 'zh_CN') : null} +
+
+ + +
+
, ]} onClick={() => { instance.toChatPage(item); From 3c1a72b8f7a983612ab23c0219ed0da85db08888 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 3 Sep 2024 13:03:14 +0800 Subject: [PATCH 59/78] chore(ui): pyproject --- .vscode/settings.json | 3 +-- packages/magent-ui/pyproject.toml | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ff5906c..1789009 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -40,8 +40,7 @@ "**/.hg": true, "**/CVS": true, "**/.DS_Store": true, - "**/Thumbs.db": true, - "**/dist": true + "**/Thumbs.db": true }, "[python]": { "editor.codeActionsOnSave": { diff --git a/packages/magent-ui/pyproject.toml b/packages/magent-ui/pyproject.toml index 105c76e..0dbebf7 100644 --- a/packages/magent-ui/pyproject.toml +++ b/packages/magent-ui/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "magent-ui" -version = "0.1.16" +version = "0.1.16.dev6" description = "" authors = [ { name = "shiyu", email = "dongyuxin.dyx@antgroup.com" }, @@ -8,9 +8,9 @@ authors = [ ] dependencies = [ - "sse-starlette>=2.1.2", - "jinja2>=3.1.4", - "python-multipart>=0.0.9", + "sse-starlette>=2.1.2", + "jinja2>=3.1.4", + "python-multipart>=0.0.9", ] readme = "README.md" requires-python = ">= 3.10" From e6fcecda6fc8ad1335dbe8e19e1860a7f49c56a7 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Tue, 3 Sep 2024 15:36:45 +0800 Subject: [PATCH 60/78] fix(ui): refetch info --- web-apps/ui/src/modules/agent/agent-market.ts | 7 ++++++- web-apps/ui/src/modules/agent/agent-model.ts | 5 +++++ web-apps/ui/src/views/agents/view.tsx | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/web-apps/ui/src/modules/agent/agent-market.ts b/web-apps/ui/src/modules/agent/agent-market.ts index 4400f01..1d07c72 100644 --- a/web-apps/ui/src/modules/agent/agent-market.ts +++ b/web-apps/ui/src/modules/agent/agent-market.ts @@ -14,7 +14,7 @@ export class AgentMarket { @prop() loading = false; - protected fetching: Promise; + protected fetching?: Promise; constructor(@inject(AgentManager) agentManager: AgentManager) { this.agentManager = agentManager; @@ -28,6 +28,11 @@ export class AgentMarket { } else { this.fetching = this.agentManager.getAll(); } + this.fetching + .then(() => { + return (this.fetching = undefined); + }) + .catch(console.error); const options = await this.fetching; this.list = options.map(this.agentManager.getOrCreate); this.loading = false; diff --git a/web-apps/ui/src/modules/agent/agent-model.ts b/web-apps/ui/src/modules/agent/agent-model.ts index 2a0b9a4..57fdb01 100644 --- a/web-apps/ui/src/modules/agent/agent-model.ts +++ b/web-apps/ui/src/modules/agent/agent-model.ts @@ -142,6 +142,11 @@ export class AgentModel extends AsyncModel { if (!this.fetching || force) { this.fetching = this.doFetchInfo(option); } + this.fetching + .then(() => { + return (this.fetching = undefined); + }) + .catch(console.error); return this.fetching; } diff --git a/web-apps/ui/src/views/agents/view.tsx b/web-apps/ui/src/views/agents/view.tsx index ba15a0f..3d0dfba 100644 --- a/web-apps/ui/src/views/agents/view.tsx +++ b/web-apps/ui/src/views/agents/view.tsx @@ -99,6 +99,7 @@ export class AgentsView extends BaseView { override view = AgentsViewComponent; @inject(AgentMarket) market: AgentMarket; + override async onViewMount(): Promise { this.loadig = true; await this.market.update(); From 6d32242ff0338392840fe2199aa59bd05bd3721a Mon Sep 17 00:00:00 2001 From: "xujingli.xjl" Date: Tue, 3 Sep 2024 17:57:06 +0800 Subject: [PATCH 61/78] =?UTF-8?q?fix:=20=E5=9C=A8=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=BF=94=E5=9B=9E=E8=BF=87=E7=A8=8B=E4=B8=AD?= =?UTF-8?q?=EF=BC=8C=E7=94=A8=E6=88=B7=E6=89=8B=E5=8A=A8=E4=B8=8A=E6=BB=91?= =?UTF-8?q?=E5=90=8E=E5=85=B3=E9=97=AD=E8=87=AA=E5=8A=A8=E4=B8=8B=E6=BB=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web-apps/ui/src/views/chat/view.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web-apps/ui/src/views/chat/view.tsx b/web-apps/ui/src/views/chat/view.tsx index 1dc3ee7..3cc0515 100644 --- a/web-apps/ui/src/views/chat/view.tsx +++ b/web-apps/ui/src/views/chat/view.tsx @@ -171,7 +171,13 @@ export class ChatView extends BaseView { id, agentId: this.agentId, }); - const toDispose = this.session.onMessage(() => setImmediate(this.scrollToBottom)); + const toDispose = this.session.onMessage(() => + setImmediate(() => { + if (!this.showToBottomBtn) { + this.scrollToBottom(); + } + }), + ); this.toDispose.push(toDispose); this.sessionDeferred.resolve(this.session); }; From 1120fdf22dd1b7b44ae8d656d75274f43d90465a Mon Sep 17 00:00:00 2001 From: "xujingli.xjl" Date: Wed, 4 Sep 2024 19:25:42 +0800 Subject: [PATCH 62/78] =?UTF-8?q?fix:=20umi=E7=89=88=E6=9C=AC=E8=BE=83?= =?UTF-8?q?=E4=BD=8E=E6=97=B6=E6=B5=81=E5=A4=B1=E8=BE=93=E5=87=BA=E6=97=A0?= =?UTF-8?q?=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web-apps/platform/src/modules/chat/chat.ts | 12 ++++++++++-- web-apps/ui/package.json | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/web-apps/platform/src/modules/chat/chat.ts b/web-apps/platform/src/modules/chat/chat.ts index dcc9c1d..8ffade9 100644 --- a/web-apps/platform/src/modules/chat/chat.ts +++ b/web-apps/platform/src/modules/chat/chat.ts @@ -232,7 +232,11 @@ export class Chat extends AsyncModel { const newMessageModel: ChatMessageModel = JSON.parse(e.data); const message = this.getOrCreateMessage(newMessageModel); this.messages = [...this.messages, message]; - setImmediate(() => this.scrollToBottom(true, false)); + setImmediate(() => { + if (!this.showToBottomBtn) { + this.scrollToBottom(true, false); + } + }); } if (e.event === 'chunk') { @@ -241,7 +245,11 @@ export class Chat extends AsyncModel { if (msg) { this.processingChunk = msg; msg.appendChunk(chunk); - setImmediate(() => this.scrollToBottom(true, false)); + setImmediate(() => { + if (!this.showToBottomBtn) { + this.scrollToBottom(true, false); + } + }); } } } catch (e) { diff --git a/web-apps/ui/package.json b/web-apps/ui/package.json index 602c95d..b5e98cc 100644 --- a/web-apps/ui/package.json +++ b/web-apps/ui/package.json @@ -48,7 +48,7 @@ "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.0", "timeago.js": "^4.0.2", - "umi": "^4.1.1" + "umi": "^4.3.18" }, "devDependencies": { "@babel/plugin-proposal-decorators": "^7.23.7", From 8e9c116d731d89d8a48d5347dec679833c94cd55 Mon Sep 17 00:00:00 2001 From: "xujingli.xjl" Date: Wed, 4 Sep 2024 19:26:40 +0800 Subject: [PATCH 63/78] =?UTF-8?q?feat:=20peer=E5=A4=9A=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E4=BD=93=E7=BB=84=E5=A4=9A=E8=BD=AE=E5=AF=B9=E8=AF=9D=E7=9A=84?= =?UTF-8?q?=E5=B1=95=E7=A4=BA;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat-message/peer-message-item-model.ts | 137 +++++++++++---- .../ui/src/modules/chat-message/protocol.ts | 9 + .../chat/components/message/peer-message.tsx | 159 +++++++++++++----- .../views/chat/components/message/peer.less | 8 + 4 files changed, 242 insertions(+), 71 deletions(-) diff --git a/web-apps/ui/src/modules/chat-message/peer-message-item-model.ts b/web-apps/ui/src/modules/chat-message/peer-message-item-model.ts index dc3debf..1353dea 100644 --- a/web-apps/ui/src/modules/chat-message/peer-message-item-model.ts +++ b/web-apps/ui/src/modules/chat-message/peer-message-item-model.ts @@ -11,6 +11,7 @@ import type { ChatEventResult, ChatEventStep, ChatEventStepQA, + StepContent, } from './protocol.js'; import { ChatMessageItemOption } from './protocol.js'; @@ -28,8 +29,8 @@ export class PeerChatMessageItem extends AIChatMessageItem { @prop() reviewingPlanner: string; - @prop() - currentStep = 0; + // @prop() + // currentStep = 0; @prop() steps: ChatEventStep[] = []; @@ -39,17 +40,27 @@ export class PeerChatMessageItem extends AIChatMessageItem { @prop() received = false; - @prop() - planningContent = ''; + // @prop() + // planningContent = ''; + + // @prop() + // executingContent: ChatEventStepQA[] = []; + + // @prop() + // expressingContent = ''; + + // @prop() + // reviewingContent = ''; @prop() - executingContent: ChatEventStepQA[] = []; + currRound: number; @prop() - expressingContent = ''; + roundsContent: StepContent[]; @prop() - reviewingContent = ''; + protected currRoundContent: StepContent; + protected _isConstructorInitialized = false; constructor( @inject(ChatMessageItemOption) option: ChatMessageItemOption, @@ -58,9 +69,35 @@ export class PeerChatMessageItem extends AIChatMessageItem { ) { super(option, axios, agentManager); this.agentReady = this.agentDeferred.promise; + this.addEmptyRoundContent(0); this.initialize(); + this._isConstructorInitialized = true; } + /** + * @param roundStartsAt 当前轮从第几步开始 + */ + protected addEmptyRoundContent = (roundStartsAt: number) => { + if (this.currRound === undefined) { + this.currRound = -1; + } + + this.currRound += 1; + this.currRoundContent = { + currentStep: 0, + roundStartsAt, // 第一轮肯定从planner开始 + planningContent: '', + executingContent: [], + expressingContent: '', + reviewingContent: '', + }; + + if (!this.roundsContent) { + this.roundsContent = []; + } + this.roundsContent.push(this.currRoundContent); + }; + override initialize = async () => { await this.getAgent(); if (!this.agent) { @@ -81,17 +118,17 @@ export class PeerChatMessageItem extends AIChatMessageItem { const expressing = members[2]; this.expressingPlanner = expressing.id; const reviewing = members[3]; - this.reviewingContent = this.contentMap[this.reviewingPlanner]; - this.planningContent = this.contentMap[this.planningPlanner]; - this.expressingContent = this.contentMap[this.expressingPlanner]; + this.currRoundContent.reviewingContent = this.contentMap[this.reviewingPlanner]; + this.currRoundContent.planningContent = this.contentMap[this.planningPlanner]; + this.currRoundContent.expressingContent = this.contentMap[this.expressingPlanner]; this.contentMap[this.expressingPlanner] = this._content; this.reviewingPlanner = reviewing.id; }; override get content(): string { - if (this.expressingContent) { - return this.expressingContent; + if (this.currRoundContent.expressingContent) { + return this.currRoundContent.expressingContent; } if (this.expressingPlanner) { return this.contentMap[this.expressingPlanner] || ''; @@ -100,8 +137,12 @@ export class PeerChatMessageItem extends AIChatMessageItem { } override set content(v) { - if (this.expressingContent) { - this.expressingContent = v; + if (!this._isConstructorInitialized) { + this._content = v; + return; + } + if (this.currRoundContent.expressingContent) { + this.currRoundContent.expressingContent = v; } if (this.expressingPlanner) { this.contentMap[this.expressingPlanner] = v; @@ -110,28 +151,62 @@ export class PeerChatMessageItem extends AIChatMessageItem { } } + /** + * + * @param agent_id 当前chunk的agent_id + * 判断当前是不是需要开启新的一轮对话执行。 + */ + protected judgeAndAddEmptyRound = (agent_id: string) => { + switch (agent_id) { + case this.planningPlanner: + case this.executingPlanner: + // expressingContent有可能是undefined + if ( + this.currRound >= 0 && + this.roundsContent[this.currRound].expressingContent && + this.roundsContent[this.currRound].expressingContent !== '' + ) { + this.addEmptyRoundContent(agent_id === this.planningPlanner ? 0 : 1); + } + break; + case this.expressingPlanner: + if ( + this.currRound >= 0 && + this.roundsContent[this.currRound].reviewingContent && // 有可能undefined + this.roundsContent[this.currRound].reviewingContent !== '' + ) { + this.addEmptyRoundContent(2); + } + break; + case this.reviewingPlanner: + // 一般不会有某一轮对话一上来就是rwviewing + break; + } + }; + override appendChunk(e: ChatEventChunk) { if (this.planningPlanner) { + this.judgeAndAddEmptyRound(e.agent_id); switch (e.agent_id) { case this.planningPlanner: - this.planningContent = `${this.planningContent || ''}${e.output || ''}`; + this.currRoundContent.planningContent = `${this.currRoundContent.planningContent || ''}${e.output || ''}`; try { - const data = JSON.parse(this.planningContent); - this.planningContent = data.thought; - this.planningContent += '\n\n'; - this.planningContent += this.toContentStr( + const data = JSON.parse(this.currRoundContent.planningContent); + this.currRoundContent.planningContent = data.thought; + this.currRoundContent.planningContent += '\n\n'; + this.currRoundContent.planningContent += this.toContentStr( data.framework as string | string[], ); - this.currentStep = 1; + this.currRoundContent.currentStep = 1; } catch (e) { // console.error(e); } break; case this.expressingPlanner: - this.expressingContent = `${this.expressingContent || ''}${e.output || ''}`; + this.currRoundContent.expressingContent = `${this.currRoundContent.expressingContent || ''}${e.output || ''}`; break; case this.reviewingPlanner: - this.reviewingContent = `${this.reviewingContent || ''}${e.output || ''}`; + this.currRoundContent.reviewingContent = `${this.currRoundContent.reviewingContent || ''}${e.output || ''}`; break; default: break; @@ -177,8 +252,8 @@ export class PeerChatMessageItem extends AIChatMessageItem { if (data.agent_id === this.reviewingPlanner) { eventStep = 3; } - if (eventStep > this.currentStep) { - this.currentStep = eventStep; + if (eventStep > this.currRoundContent.currentStep) { + this.currRoundContent.currentStep = eventStep; } if (e.event === 'result') { @@ -196,28 +271,32 @@ export class PeerChatMessageItem extends AIChatMessageItem { override handleSteps(e: ChatEventStep): void { let eventStep = 0; + if (e.agent_id === this.planningPlanner) { eventStep = 1; } if (e.agent_id === this.executingPlanner) { eventStep = 2; - this.executingContent = e.output as ChatEventStepQA[]; + this.currRoundContent.executingContent = e.output as ChatEventStepQA[]; } if (e.agent_id === this.expressingPlanner) { eventStep = 3; } if (e.agent_id === this.reviewingPlanner) { eventStep = 4; - this.reviewingContent = this.toContentStr(e.output as string | string[]); + this.currRoundContent.reviewingContent = this.toContentStr( + e.output as string | string[], + ); } - if (eventStep > this.currentStep) { - this.currentStep = eventStep; + if (eventStep > this.currRoundContent.currentStep) { + this.currRoundContent.currentStep = eventStep; } this.steps[eventStep] = e; } override handleResult(e: ChatEventResult): void { super.handleResult(e); - this.currentStep = 4; + const currRoundContent = this.roundsContent[this.currRound]; // TODO: 具体第几轮 + currRoundContent.currentStep = 4; } } diff --git a/web-apps/ui/src/modules/chat-message/protocol.ts b/web-apps/ui/src/modules/chat-message/protocol.ts index a01b2c3..8259ba2 100644 --- a/web-apps/ui/src/modules/chat-message/protocol.ts +++ b/web-apps/ui/src/modules/chat-message/protocol.ts @@ -15,6 +15,15 @@ export interface MessageCreate { stream?: boolean; } +export interface StepContent { + currentStep: number; // 0-4 + roundStartsAt: number; // 0-4 + planningContent: string; + executingContent: ChatEventStepQA[]; + expressingContent: string; + reviewingContent: string; +} + export interface MessageItem { senderType?: MessageSender; content: string; diff --git a/web-apps/ui/src/views/chat/components/message/peer-message.tsx b/web-apps/ui/src/views/chat/components/message/peer-message.tsx index 6911553..27aeb24 100644 --- a/web-apps/ui/src/views/chat/components/message/peer-message.tsx +++ b/web-apps/ui/src/views/chat/components/message/peer-message.tsx @@ -5,14 +5,16 @@ import { LoadingOutlined, } from '@ant-design/icons'; import { useInject, useObserve, ViewInstance } from '@difizen/mana-app'; +import type { StepProps } from 'antd'; import { Collapse, Steps } from 'antd'; import classNames from 'classnames'; import copy from 'copy-to-clipboard'; -import type { ReactNode } from 'react'; +import { useEffect, useState, type ReactNode } from 'react'; import { AgentIcon } from '@/modules/agent/agent-icon.js'; import type { ChatMessageModel } from '@/modules/chat-message/chat-message-model.js'; import type { PeerChatMessageItem } from '@/modules/chat-message/peer-message-item-model.js'; +import type { StepContent } from '@/modules/chat-message/protocal.js'; import type { ChatEventStepQA } from '@/modules/chat-message/protocol.js'; import { AnswerState } from '@/modules/chat-message/protocol.js'; @@ -86,6 +88,117 @@ export const MarkdownThought = (props: { content: string }) => { ); }; +const StepsInMessage = (props: { content: StepContent; isLast: boolean }) => { + return ( + + ), + icon: props.content.currentStep === 0 ? : undefined, + } + : (undefined as unknown as StepProps), + props.content.roundStartsAt <= 1 + ? { + title: 'Executing', + description: , + icon: props.content.currentStep === 1 ? : undefined, + } + : (undefined as unknown as StepProps), + props.content.roundStartsAt <= 2 + ? { + title: 'Expressing', + description: ( + + ), + icon: props.content.currentStep === 2 ? : undefined, + } + : (undefined as unknown as StepProps), + { + title: 'Reviewing', + description: , + icon: props.content.currentStep === 3 ? : undefined, + }, + ].filter((i) => i !== undefined) as StepProps[] + } + /> + ); +}; + +const MultiStepRoundMessage = (props: { + roundsContent: StepContent[]; + exchange: ChatMessageModel; +}) => { + const [activeKey, setActiveKey] = useState([]); + + useEffect(() => { + // 每次 roundsContent 变化时,设置 activeKey 为最后一项 + const lastIndex = props.roundsContent.length - 1; + if (lastIndex >= 0) { + setActiveKey([`round${lastIndex}`]); + } else { + setActiveKey([]); // 如果 roundsContent 为空,则不展开 + } + }, [props.roundsContent.length]); + + const handleChange = (key: string | string[]) => { + // 更新 activeKey,支持多项展开 + setActiveKey((prevActiveKey) => { + if (Array.isArray(key)) { + return key; + } + const index = prevActiveKey.indexOf(key as string); + if (index > -1) { + return prevActiveKey.filter((k) => k !== key); + } else { + return [...prevActiveKey, key as string]; + } + }); + }; + + return props.roundsContent.map((content, idx) => { + return ( + + ), + }, + ]} + /> + ); + }); +}; + export const AIMessageContent = (props: AIMessageProps) => { const message = useObserve(props.message); const exchange = useObserve(props.exchange); @@ -109,47 +222,9 @@ export const AIMessageContent = (props: AIMessageProps) => { key: 'peer', label: `${message.agent?.name} ${exchange.tokenUsage ? '思考过程' : '思考中...'}`, children: ( - - ), - icon: message.currentStep === 0 ? : undefined, - }, - { - title: 'Executing', - description: , - icon: message.currentStep === 1 ? : undefined, - }, - { - title: 'Expressing', - description: ( - - ), - icon: message.currentStep === 2 ? : undefined, - }, - { - title: 'Reviewing', - description: ( - - ), - icon: message.currentStep === 3 ? : undefined, - }, - ]} + ), }, diff --git a/web-apps/ui/src/views/chat/components/message/peer.less b/web-apps/ui/src/views/chat/components/message/peer.less index ccc4062..a33d50f 100644 --- a/web-apps/ui/src/views/chat/components/message/peer.less +++ b/web-apps/ui/src/views/chat/components/message/peer.less @@ -16,3 +16,11 @@ padding: 12px 24px; } } + +.chat-message-peer-multi-round-container { + margin-top: 14px; + + .ant-collapse-item { + padding-bottom: 14px; + } +} From cf20c8d93ff44b7fa73c7f369efba48662fb5637 Mon Sep 17 00:00:00 2001 From: "yukun.wyk" Date: Sun, 8 Sep 2024 23:58:11 +0800 Subject: [PATCH 64/78] chore(flow): typo fix --- web-packages/magent-flow/.eslintrc.mjs | 96 ++++++++++++++++++- web-packages/magent-flow/package.json | 5 +- web-packages/magent-flow/src/common/icons.ts | 3 - .../AIBasic/CascaderInNode/index.tsx | 4 +- .../components/AIBasic/PromptEditor/index.tsx | 2 +- .../plugins/component-picker-block/hooks.tsx | 2 +- .../plugins/component-picker-block/index.tsx | 14 +-- .../PromptEditor/plugins/placeholder.tsx | 2 +- .../PromptEditor/plugins/update-block.tsx | 3 +- .../components/AIBasic/PromptEditor/utils.ts | 3 +- .../components/AIBasic/SelectInNode/index.tsx | 3 +- .../src/components/ConditionForm/index.tsx | 5 +- .../magent-flow/src/components/Flow/index.tsx | 5 +- .../magent-flow/src/components/Flow/keys.ts | 9 +- .../src/components/Node/AgentNode/index.tsx | 4 +- .../src/components/Node/CommonNode/index.tsx | 28 +++--- .../src/components/Node/EndNode/index.tsx | 13 +-- .../src/components/Node/IfElseNode/index.tsx | 7 +- .../components/Node/KnowledgeNode/index.tsx | 9 +- .../src/components/Node/LLMNode/index.tsx | 10 +- .../Node/NodeWrapper/Status/index.tsx | 21 ++-- .../src/components/ReferenceForm/index.tsx | 21 ++-- .../src/components/VariableForm/index.tsx | 24 +++-- .../src/stores/useKnowledgeStore.ts | 2 +- .../magent-flow/src/stores/useModelStore.ts | 2 +- .../src/stores/useShortcutsStore.ts | 2 +- .../magent-flow/src/typings/index.d.ts | 1 + 27 files changed, 193 insertions(+), 107 deletions(-) delete mode 100644 web-packages/magent-flow/src/common/icons.ts create mode 100644 web-packages/magent-flow/src/typings/index.d.ts diff --git a/web-packages/magent-flow/.eslintrc.mjs b/web-packages/magent-flow/.eslintrc.mjs index ffd7daa..c319428 100644 --- a/web-packages/magent-flow/.eslintrc.mjs +++ b/web-packages/magent-flow/.eslintrc.mjs @@ -1,3 +1,97 @@ module.exports = { - extends: require.resolve('../../.eslintrc.js'), + root: true, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react/recommended', + 'plugin:react-hooks/recommended', + 'plugin:promise/recommended', + 'prettier', + ], + plugins: ['import'], + + env: { + node: true, + }, + settings: { + react: { + version: '18', + }, + }, + + rules: { + // common pitfalls + eqeqeq: 'error', + curly: 'error', + + // stricter type correctness + // 'no-unused-vars': [ + // 'warn', + // { + // vars: 'local', + // args: 'none', + // destructuredArrayIgnorePattern: '^_', + // ignoreRestSiblings: true, + // argsIgnorePattern: '^_', + // caughtErrors: 'none', + // }, + // ], + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-explicit-any': ['warn', { ignoreRestArgs: true }], + '@typescript-eslint/no-shadow': [ + 'warn', + { + ignoreTypeValueShadow: true, + }, + ], + + // react rules + 'react-hooks/exhaustive-deps': 'error', + 'react-hooks/rules-of-hooks': 'error', + 'react/jsx-uses-react': 'off', + 'react/react-in-jsx-scope': 'off', + + // no sloppiness + 'no-console': ['error', { allow: ['error', 'warn', 'info'] }], + + // import rules and fixes + '@typescript-eslint/consistent-type-imports': 'error', + 'import/newline-after-import': 'warn', + 'import/order': [ + 'warn', + { + pathGroups: [ + { + pattern: '@/**', + group: 'internal', + position: 'before', + }, + ], + distinctGroup: false, + groups: [ + 'builtin', + 'external', + 'internal', + 'parent', + 'sibling', + 'index', + 'object', + ], + 'newlines-between': 'always', + alphabetize: { + order: 'asc', + caseInsensitive: true, + }, + }, + ], + }, + + overrides: [ + { + files: ['*.js', '*.cjs', '*.mjs', '*.jsx'], + rules: { + '@typescript-eslint/no-var-requires': 'off', + }, + }, + ], }; diff --git a/web-packages/magent-flow/package.json b/web-packages/magent-flow/package.json index 1ce039c..89e60a1 100644 --- a/web-packages/magent-flow/package.json +++ b/web-packages/magent-flow/package.json @@ -52,6 +52,7 @@ "@floating-ui/react": "^0.26.22", "@lexical/code": "^0.17.0", "@lexical/react": "^0.17.0", + "@lexical/text": "^0.17.1", "@lexical/utils": "^0.17.0", "@types/json-schema": "^7.0.15", "@xyflow/react": "^12.0.2", @@ -74,11 +75,13 @@ "@types/js-yaml": "^4.0.9", "@types/lodash": "^4.17.7", "@types/react": "^18.2.25", + "@types/react-dom": "^18.2.18", "@types/uuid": "^10.0.0", "tailwindcss": "^3" }, "peerDependencies": { "antd": "^5.8.6", - "react": ">=16" + "react": ">=16", + "react-dom": "^18.0.0" } } diff --git a/web-packages/magent-flow/src/common/icons.ts b/web-packages/magent-flow/src/common/icons.ts deleted file mode 100644 index 42793c3..0000000 --- a/web-packages/magent-flow/src/common/icons.ts +++ /dev/null @@ -1,3 +0,0 @@ -// export const IconMap = { -// LLM: -// } diff --git a/web-packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx b/web-packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx index 3c65e42..7ff6741 100644 --- a/web-packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/CascaderInNode/index.tsx @@ -1,8 +1,6 @@ +import { classNames } from '@flow/utils/index.js'; import type { CascaderProps } from 'antd'; import { Cascader } from 'antd'; -import React from 'react'; - -import { classNames } from '@flow/utils/index.js'; export const CascaderInNode = (props: CascaderProps) => { return ( diff --git a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx index a3bbed7..38f7504 100644 --- a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/index.tsx @@ -99,7 +99,7 @@ export const PromptEditor: FC = ({ compact={compact} /> } - ErrorBoundary={LexicalErrorBoundary} + ErrorBoundary={LexicalErrorBoundary as any} /> ); }, - [ - allFlattenOptions.length, - refs, - isPositioned, - floatingStyles, - queryString, - handleSelectWorkflowVariable, - ], + [allFlattenOptions.length, refs, isPositioned, floatingStyles, queryString], ); return ( diff --git a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx index a98915a..6580ae4 100644 --- a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/placeholder.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames'; -import React, { memo } from 'react'; +import { memo } from 'react'; const Placeholder = ({ compact, diff --git a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx index 1f8a36c..e98dc23 100644 --- a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/plugins/update-block.tsx @@ -1,8 +1,7 @@ +import { useEventEmitterContextContext } from '@flow/context/event-emitter.js'; import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { $insertNodes } from 'lexical'; -import { useEventEmitterContextContext } from '@flow/context/event-emitter.js'; - import { textToEditorState } from '../utils.js'; import { CustomTextNode } from './custom-text/node.js'; diff --git a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts index ca1f1cb..52bbf68 100644 --- a/web-packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts +++ b/web-packages/magent-flow/src/components/AIBasic/PromptEditor/utils.ts @@ -74,6 +74,7 @@ export function registerLexicalTextEntity( } } + // eslint-disable-next-line no-constant-condition while (true) { match = getMatch(text); let nextText = match === null ? '' : text.slice(match.end); @@ -126,7 +127,7 @@ export function registerLexicalTextEntity( replacementNode.setFormat(nodeToReplace.getFormat()); nodeToReplace.replace(replacementNode); - if (currentNode == null) { + if (currentNode === null) { return; } } diff --git a/web-packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx b/web-packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx index de2a69f..52b5414 100644 --- a/web-packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx +++ b/web-packages/magent-flow/src/components/AIBasic/SelectInNode/index.tsx @@ -1,8 +1,7 @@ +import { classNames } from '@flow/utils/index.js'; import type { SelectProps } from 'antd'; import { Select } from 'antd'; -import { classNames } from '@flow/utils/index.js'; - export const SelectInNode = (props: SelectProps) => { return (