Compare commits
48 Commits
fix/ci
...
feat/chatf
| Author | SHA1 | Date | |
|---|---|---|---|
| ab465ff3eb | |||
| 0d5c330b51 | |||
| e678c24b0c | |||
| 13d30605f1 | |||
| 03b8d8e17a | |||
| e3930873c6 | |||
| 2ed2a60479 | |||
| f589bb94bb | |||
| 02b4171576 | |||
| 0d83a5e7bc | |||
| 14ca189316 | |||
| 4310dee4c2 | |||
| 4ca3e597ff | |||
| 53345f58c2 | |||
| 8137b0aee5 | |||
| b48c4c2792 | |||
| f8840810ce | |||
| 9b68bd5387 | |||
| a6f97f61f8 | |||
| 0965d69acc | |||
| 183d0324bb | |||
| 04f0491454 | |||
| 9ed2f8be67 | |||
| 403128b5d3 | |||
| db7c95885d | |||
| 2ee3fa68ab | |||
| a0d3bcf998 | |||
| cc593fc270 | |||
| 6e961bb60d | |||
| f93b60512f | |||
| 9dcdb70508 | |||
| 4a44c0ddbd | |||
| b299adacf3 | |||
| 0ce6a4da4c | |||
| be5178d57b | |||
| 2d925ca241 | |||
| 60a9c7a281 | |||
| 376e563e4f | |||
| f0c339d231 | |||
| 81b5867a62 | |||
| 5ac7b8d26e | |||
| 48b52c3592 | |||
| 033df3f8ee | |||
| f294e19af5 | |||
| 23a1f1cab0 | |||
| c3d8def0e6 | |||
| 32d9bf9a39 | |||
| be4aa3f2ca |
540
.github/CODEOWNERS
vendored
540
.github/CODEOWNERS
vendored
@ -1,268 +1,274 @@
|
||||
* Tecvan-fe
|
||||
* @Tecvan-fe @hi-pender @fanlv
|
||||
|
||||
/apps/coze-studio/ @Tecvan-fe @evan-crash @duwenhan2byte
|
||||
/packages/agent-ide/agent-publish/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei @catee
|
||||
/packages/agent-ide/commons/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/arch/bot-api/ @Tecvan-fe
|
||||
/packages/arch/bot-http/ @Tecvan-fe
|
||||
/packages/arch/logger/ @Tecvan-fe
|
||||
/packages/arch/slardar-interface/ @Tecvan-fe @evan-crash
|
||||
/config/eslint-config/ @Tecvan-fe @leeight @soonco
|
||||
/infra/eslint-plugin/ @Tecvan-fe
|
||||
/config/ts-config/ @leeight @Tecvan-fe
|
||||
/config/vitest-config/ @Tecvan-fe
|
||||
/packages/arch/bot-env/ @Tecvan-fe @leeight
|
||||
/packages/arch/bot-env-adapter/ @dragooncjw @Tecvan-fe @leeight
|
||||
/packages/arch/bot-typings/ @Tecvan-fe
|
||||
/packages/arch/web-context/ @Tecvan-fe
|
||||
/packages/components/bot-semi/ @Tecvan-fe
|
||||
/packages/components/bot-icons/ @DingGao-Devin
|
||||
/packages/arch/i18n/ @Tecvan-fe @leeight
|
||||
/packages/arch/resources/studio-i18n-resource/ @dragooncjw @Tecvan-fe
|
||||
/config/stylelint-config/ @Tecvan-fe
|
||||
/packages/arch/idl/ @Tecvan-fe
|
||||
/infra/utils/fs-enhance/ @Tecvan-fe
|
||||
/packages/arch/bot-store/ @Tecvan-fe @catee @duwenhan2byte
|
||||
/packages/arch/bot-error/ @haozhenfei @duwenhan2byte
|
||||
/packages/foundation/space-store/ @evan-crash @duwenhan2byte
|
||||
/packages/arch/bot-flags/ @Tecvan-fe
|
||||
/packages/arch/report-events/ @Tecvan-fe
|
||||
/packages/foundation/enterprise-store-adapter/ @evan-crash @duwenhan2byte
|
||||
/packages/foundation/local-storage/ @duwenhan2byte @evan-crash
|
||||
/packages/foundation/space-store-adapter/ @evan-crash @duwenhan2byte
|
||||
/packages/arch/bot-tea/ @Tecvan-fe @catee @soonco
|
||||
/packages/arch/tea/ @Tecvan-fe @evan-crash @soonco
|
||||
/packages/arch/tea-adapter/ @dragooncjw @Tecvan-fe
|
||||
/packages/arch/tea-interface/ @dragooncjw @Tecvan-fe
|
||||
/packages/studio/stores/bot-detail/ @Hezi-crypto @catee @DingGao-Devin @duwenhan2byte @evan-crash
|
||||
/packages/agent-ide/bot-input-length-limit/ @Hezi-crypto @catee @duwenhan2byte
|
||||
/packages/agent-ide/tool-config/ @haozhenfei @catee
|
||||
/packages/arch/bot-space-api/ @Tecvan-fe @duwenhan2byte
|
||||
/packages/arch/bot-utils/ @Tecvan-fe
|
||||
/packages/common/uploader-adapter/ @dragooncjw @Tecvan-fe
|
||||
/packages/common/uploader-interface/ @dragooncjw @Tecvan-fe
|
||||
/packages/studio/user-store/ @duwenhan2byte @catee @lihuiwen
|
||||
/packages/arch/foundation-sdk/ @evan-crash @duwenhan2byte
|
||||
/packages/common/chat-area/chat-core/ @haozhenfei @Hezi-crypto @evan-crash
|
||||
/packages/common/chat-area/utils/ @Hezi-crypto @haozhenfei
|
||||
/packages/arch/bot-md-box-adapter/ @Hezi-crypto @iu1340 @dragooncjw @Tecvan-fe
|
||||
/packages/studio/common/file-kit/ @haozhenfei @evan-crash
|
||||
/packages/arch/slardar-adapter/ @Tecvan-fe @dragooncjw
|
||||
/packages/arch/default-slardar/ @Tecvan-fe @evan-crash
|
||||
/packages/arch/fetch-stream/ @Hezi-crypto @haozhenfei
|
||||
/packages/common/websocket-manager-adapter/ @haozhenfei @Hezi-crypto @catee
|
||||
/packages/studio/autosave/ @catee
|
||||
/packages/studio/bot-utils/ @catee @soonco @Hezi-crypto
|
||||
/packages/common/flowgram-adapter/common/ @zxhfighter @xiamidaxia @dragooncjw
|
||||
/packages/common/flowgram-adapter/free-layout-editor/ @zxhfighter @xiamidaxia @dragooncjw
|
||||
/packages/agent-ide/space-bot/ @soonco @evan-crash @duwenhan2byte @catee @DingGao-Devin
|
||||
/packages/agent-ide/space-bot/src/store/bot-list-filter/ @duwenhan2byte @lihuiwen
|
||||
/packages/agent-ide/space-bot/src/store/bot-page/ @DingGao-Devin
|
||||
/packages/agent-ide/space-bot/src/store/explore/ @Tecvan-fe
|
||||
/packages/agent-ide/space-bot/src/store/risk-warning/ @lihuiwen @catee
|
||||
/packages/agent-ide/context/ @evan-crash
|
||||
/packages/agent-ide/bot-editor-context-store/ @Hezi-crypto @duwenhan2byte @catee
|
||||
/packages/agent-ide/chat-background/ @catee
|
||||
/packages/agent-ide/chat-background-config-content-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/chat-background-config-content/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/chat-background-shared/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/common/chat-area/chat-uikit/ @catee @Hezi-crypto @evan-crash @haozhenfei
|
||||
/packages/common/chat-area/hooks/ @Hezi-crypto @evan-crash
|
||||
/packages/common/chat-area/chat-uikit-shared/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/bot-audit-adapter/ @evan-crash @duwenhan2byte @Hezi-crypto @haozhenfei
|
||||
/packages/agent-ide/bot-audit-base/ @evan-crash @duwenhan2byte @Hezi-crypto @haozhenfei
|
||||
/packages/studio/components/ @soonco @evan-crash @duwenhan2byte @catee
|
||||
/packages/arch/bot-hooks/ @catee @Tecvan-fe @soonco
|
||||
/packages/arch/bot-hooks/src/page-jump/ @evan-crash @catee
|
||||
/packages/arch/bot-hooks-adapter/ @catee @Tecvan-fe @soonco
|
||||
/packages/arch/bot-hooks-base/ @catee @Tecvan-fe @soonco
|
||||
/packages/arch/responsive-kit/ @Tecvan-fe @DingGao-Devin
|
||||
/packages/common/chat-area/chat-area/ @Hezi-crypto @haozhenfei @evan-crash @haozhenfei
|
||||
/packages/data/memory/llm-plugins/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/data/common/reporter/ @soonco @catee @evan-crash
|
||||
/packages/components/json-viewer/ @duwenhan2byte
|
||||
/packages/components/scroll-view/ @evan-crash
|
||||
/packages/common/assets/ @Tecvan-fe @catee
|
||||
/packages/common/biz-components/ @duwenhan2byte
|
||||
/packages/data/common/e2e/ @soonco @catee @evan-crash @haozhenfei @duwenhan2byte
|
||||
/packages/agent-ide/debug-tool-list/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/model-manager/ @Hezi-crypto @catee
|
||||
/packages/agent-ide/model-manager/src/components/multi-agent/ @catee
|
||||
/packages/agent-ide/tool/ @catee
|
||||
/packages/data/knowledge/knowledge-modal-base/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/components/biz-tooltip-ui/ @Hezi-crypto @catee @evan-crash
|
||||
/packages/components/table-view/ @lihuiwen
|
||||
/packages/components/virtual-list/ @Tecvan-fe
|
||||
/packages/data/common/utils/ @soonco @catee @evan-crash
|
||||
/packages/data/knowledge/knowledge-resource-processor-core/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/arch/pdfjs-shadow/ @Tecvan-fe
|
||||
/packages/data/knowledge/common/stores/ @soonco @catee @evan-crash
|
||||
/packages/foundation/global-store/ @duwenhan2byte @evan-crash
|
||||
/config/postcss-config/ @Tecvan-fe
|
||||
/config/tailwind-config/ @Tecvan-fe
|
||||
/infra/utils/monorepo-kits/ @Tecvan-fe @evan-crash
|
||||
/packages/studio/premium/premium-components-adapter/ @evan-crash
|
||||
/packages/studio/premium/premium-store-adapter/ @evan-crash
|
||||
/packages/agent-ide/onboarding/ @Hezi-crypto @catee
|
||||
/packages/agent-ide/publish-to-base/ @catee
|
||||
/packages/arch/report-tti/ @duwenhan2byte
|
||||
/packages/data/memory/database-creator/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/arch/hooks/ @Tecvan-fe @evan-crash
|
||||
/packages/common/coze-mitt/ @evan-crash @duwenhan2byte
|
||||
/packages/common/editor-plugins/ @haozhenfei @stream-pipe @Hezi-crypto
|
||||
/packages/common/md-editor-adapter/ @haozhenfei @Hezi-crypto @catee
|
||||
/packages/common/prompt-kit/main/ @haozhenfei @Hezi-crypto @catee
|
||||
/packages/common/chat-area/chat-answer-action/ @Hezi-crypto @haozhenfei @lihuiwen
|
||||
/packages/common/chat-area/plugin-message-grab/ @Hezi-crypto @haozhenfei
|
||||
/packages/common/chat-area/text-grab/ @Hezi-crypto @haozhenfei
|
||||
/packages/common/prompt-kit/adapter/ @haozhenfei @Hezi-crypto @catee
|
||||
/packages/common/prompt-kit/base/ @haozhenfei @Hezi-crypto @catee
|
||||
/packages/data/memory/database/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/data/knowledge/knowledge-resource-processor-base/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/arch/utils/ @Tecvan-fe @evan-crash
|
||||
/packages/data/knowledge/common/components/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/data/common/feature-register/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/data/knowledge/common/hooks/ @Hezi-crypto @catee @evan-crash
|
||||
/packages/data/knowledge/common/services/ @Hezi-crypto @catee @evan-crash
|
||||
/packages/data/memory/database-v2-main/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/data/memory/database-v2-adapter/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/data/memory/database-v2-base/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/data/knowledge/knowledge-data-set-for-agent/ @Hezi-crypto @catee @evan-crash
|
||||
/packages/data/knowledge/knowledge-ide-base/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/arch/bot-monaco-editor/ @Tecvan-fe
|
||||
/packages/data/knowledge/knowledge-modal-adapter/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/data/knowledge/knowledge-resource-processor-adapter/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/devops/debug/debug-panel/ @soonco @evan-crash @catee
|
||||
/packages/devops/json-link-preview/ @Maidang1 @Zhangchi123456
|
||||
/packages/devops/common-modules/ @duwenhan2byte @evan-crash @catee
|
||||
/packages/foundation/account-adapter/ @duwenhan2byte @evan-crash
|
||||
/packages/foundation/account-base/ @evan-crash @duwenhan2byte
|
||||
/packages/arch/api-schema/ @Tecvan-fe @evan-crash
|
||||
/infra/idl/idl2ts-runtime/ @Tecvan-fe @evan-crash
|
||||
/infra/idl/idl2ts-cli/ @Tecvan-fe @evan-crash
|
||||
/infra/idl/idl2ts-generator/ @Tecvan-fe @evan-crash
|
||||
/infra/idl/idl-parser/ @Tecvan-fe @evan-crash
|
||||
/infra/utils/rush-logger/ @catee @Tecvan-fe
|
||||
/infra/idl/idl2ts-helper/ @Tecvan-fe @evan-crash
|
||||
/infra/idl/idl2ts-plugin/ @Tecvan-fe @evan-crash
|
||||
/packages/studio/open-platform/open-env-adapter/ @soonco @Hezi-crypto @DingGao-Devin
|
||||
/infra/plugins/pkg-root-webpack-plugin/ @Tecvan-fe
|
||||
/packages/studio/publish-manage-hooks/ @duwenhan2byte @evan-crash
|
||||
/packages/foundation/layout/ @evan-crash @duwenhan2byte
|
||||
/packages/studio/open-platform/open-auth/ @evan-crash @DingGao-Devin
|
||||
/packages/agent-ide/entry-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/entry/ @soonco @duwenhan2byte @catee @evan-crash
|
||||
/packages/agent-ide/bot-config-area-adapter/ @haozhenfei @Hezi-crypto @duwenhan2byte @catee @evan-crash
|
||||
/packages/agent-ide/bot-config-area/ @haozhenfei @Hezi-crypto @duwenhan2byte @catee @evan-crash
|
||||
/packages/agent-ide/bot-plugin/entry/ @evan-crash @lihuiwen @catee
|
||||
/packages/agent-ide/bot-plugin/export/ @lihuiwen @catee
|
||||
/packages/agent-ide/bot-plugin/mock-set/ @lihuiwen @catee @duwenhan2byte
|
||||
/packages/studio/mockset-edit-modal-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/studio/mockset-shared/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/studio/mockset-editor/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/studio/mockset-editor-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/bot-plugin/tools/ @lihuiwen @catee
|
||||
/packages/studio/stores/bot-plugin/ @lihuiwen @Hezi-crypto @catee
|
||||
/packages/studio/plugin-shared/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/plugin-modal-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/plugin-shared/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/community/component/ @DingGao-Devin @Hezi-crypto @evan-crash @duwenhan2byte
|
||||
/packages/studio/plugin-form-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/workflow/base/ @xiamidaxia @zxhfighter
|
||||
/packages/agent-ide/plugin-content-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/plugin-content/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/plugin-setting-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/plugin-setting/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/bot-plugin/plugin-risk-warning/ @catee @evan-crash
|
||||
/packages/studio/plugin-publish-ui-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/studio/plugin-tool-columns-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/studio/plugin-tool-columns/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/chat-debug-area/ @soonco @duwenhan2byte @catee @Hezi-crypto @haozhenfei @evan-crash
|
||||
/packages/agent-ide/chat-answer-action-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/chat-area-plugin-debug-common/ @Hezi-crypto @haozhenfei
|
||||
/packages/agent-ide/chat-components-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/common/chat-area/plugin-chat-background/ @Tecvan-fe
|
||||
/packages/common/chat-area/chat-area-plugin-reasoning/ @catee @Hezi-crypto
|
||||
/packages/common/chat-area/plugin-resume/ @Tecvan-fe
|
||||
/packages/common/chat-area/plugin-chat-shortcuts/ @haozhenfei @duwenhan2byte @Hezi-crypto
|
||||
/packages/workflow/sdk/ @zxhfighter @xiamidaxia
|
||||
/packages/workflow/components/ @LLLLeeJ @zxhfighter
|
||||
/packages/components/loading-button/ @catee
|
||||
/packages/components/mouse-pad-selector/ @zxhfighter
|
||||
/packages/workflow/adapter/resources/ @LLLLeeJ @JxJuly @xiamidaxia @luics @zxhfighter @stream-pipe
|
||||
/packages/common/chat-area/chat-workflow-render/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/onboarding-message-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/plugin-area-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/prompt-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/prompt/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/workflow/ @soonco @duwenhan2byte @catee
|
||||
/packages/agent-ide/navigate/ @soonco @duwenhan2byte @catee
|
||||
/packages/agent-ide/workflow-as-agent-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/workflow-item/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/workflow-card-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/workflow-modal/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/memory-tool-pane-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/skills-pane-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/layout-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/layout/ @soonco @duwenhan2byte @catee
|
||||
/packages/agent-ide/chat-area-provider-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/agent-ide/chat-area-provider/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/studio/entity-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/foundation/account-ui-adapter/ @duwenhan2byte @evan-crash
|
||||
/packages/foundation/account-ui-base/ @evan-crash @duwenhan2byte
|
||||
/packages/foundation/foundation-sdk/ @evan-crash @duwenhan2byte
|
||||
/packages/foundation/global/ @evan-crash @duwenhan2byte
|
||||
/packages/studio/workspace/project-entity-adapter/ @Hezi-crypto @catee @duwenhan2byte
|
||||
/packages/studio/workspace/project-entity-base/ @Hezi-crypto @catee @duwenhan2byte
|
||||
/packages/foundation/global-adapter/ @evan-crash @duwenhan2byte
|
||||
/packages/foundation/browser-upgrade-banner/ @evan-crash @duwenhan2byte
|
||||
/packages/foundation/space-ui-adapter/ @evan-crash @duwenhan2byte
|
||||
/packages/foundation/space-ui-base/ @evan-crash @duwenhan2byte
|
||||
/packages/common/auth/ @evan-crash @duwenhan2byte
|
||||
/packages/common/auth-adapter/ @evan-crash @duwenhan2byte
|
||||
/packages/project-ide/main/ @dragooncjw @JxJuly @xiamidaxia @catee @lihuiwen
|
||||
/packages/components/resource-tree/ @dragooncjw @xiamidaxia @JxJuly
|
||||
/packages/common/flowgram-adapter/fixed-layout-editor/ @zxhfighter @xiamidaxia @dragooncjw
|
||||
/packages/project-ide/biz-components/ @zxhfighter @xiamidaxia
|
||||
/packages/project-ide/framework/ @dragooncjw @JxJuly @xiamidaxia
|
||||
/packages/project-ide/base-adapter/ @dragooncjw @xiamidaxia
|
||||
/packages/project-ide/base-interface/ @dragooncjw @xiamidaxia
|
||||
/packages/project-ide/client/ @dragooncjw @JxJuly @xiamidaxia
|
||||
/packages/project-ide/core/ @dragooncjw @JxJuly @xiamidaxia
|
||||
/packages/project-ide/view/ @dragooncjw @JxJuly @xiamidaxia
|
||||
/packages/project-ide/biz-data/ @haozhenfei @lihuiwen @catee @soonco
|
||||
/packages/data/knowledge/knowledge-ide-adapter/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/data/memory/variables/ @haozhenfei @catee @Hezi-crypto
|
||||
/packages/project-ide/biz-plugin/ @xiamidaxia @lihuiwen @catee
|
||||
/packages/project-ide/biz-plugin-registry-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/packages/project-ide/biz-workflow/ @dragooncjw @JxJuly @xiamidaxia
|
||||
/packages/studio/open-platform/open-chat/ @soonco @Hezi-crypto @DingGao-Devin
|
||||
/packages/workflow/playground/ @LLLLeeJ @xiamidaxia @luics @zxhfighter
|
||||
/packages/arch/load-remote-worker/ @Tecvan-fe
|
||||
/packages/devops/mockset-manage/ @soonco @evan-crash @catee
|
||||
/packages/devops/testset-manage/ @mocayo @JxJuly
|
||||
/packages/workflow/adapter/base/ @LLLLeeJ @JxJuly @xiamidaxia @luics @zxhfighter @stream-pipe
|
||||
/packages/workflow/adapter/code-editor/ @LLLLeeJ @JxJuly @xiamidaxia @luics @zxhfighter @stream-pipe
|
||||
/packages/workflow/fabric-canvas/ @xiamidaxia @zxhfighter
|
||||
/packages/workflow/feature-encapsulate/ @zxhfighter
|
||||
/packages/workflow/nodes/ @xiamidaxia @zxhfighter
|
||||
/packages/workflow/setters/ @Tecvan-fe
|
||||
/packages/workflow/variable/ @zxhfighter @LLLLeeJ @xiamidaxia
|
||||
/packages/workflow/render/ @dragooncjw @xiamidaxia
|
||||
/packages/workflow/history/ @xiamidaxia @zxhfighter
|
||||
/packages/workflow/adapter/nodes/ @LLLLeeJ @JxJuly @xiamidaxia @luics @zxhfighter @stream-pipe
|
||||
/packages/workflow/test-run/ @JxJuly @xiamidaxia @luics @zxhfighter @dragooncjw
|
||||
/packages/workflow/test-run-next/main/ @JxJuly @LLLLeeJ @xiamidaxia @zxhfighter
|
||||
/packages/workflow/test-run-next/form/ @JxJuly @LLLLeeJ @xiamidaxia @zxhfighter
|
||||
/packages/workflow/test-run-next/shared/ @JxJuly @LLLLeeJ @xiamidaxia @zxhfighter
|
||||
/packages/workflow/test-run-next/trace/ @JxJuly @LLLLeeJ @xiamidaxia @zxhfighter
|
||||
/packages/project-ide/ui-adapter/ @dragooncjw @xiamidaxia
|
||||
/packages/studio/workspace/project-publish/ @catee @lihuiwen
|
||||
/packages/studio/workspace/entry-adapter/ @duwenhan2byte @evan-crash
|
||||
/packages/studio/workspace/entry-base/ @duwenhan2byte @catee @evan-crash
|
||||
/packages/workflow/adapter/playground/ @LLLLeeJ @JxJuly @xiamidaxia @luics @zxhfighter @stream-pipe
|
||||
/infra/plugins/import-watch-loader/ @Tecvan-fe
|
||||
/config/rsbuild-config/ @Tecvan-fe
|
||||
/packages/community/explore/ @evan-crash @duwenhan2byte
|
||||
/common/_templates/node-core/ @Tecvan-fe
|
||||
/common/_templates/rspack-web/ @Tecvan-fe
|
||||
/frontend/apps/coze-studio/ @Tecvan-fe @evan-crash @duwenhan2byte
|
||||
/frontend/packages/agent-ide/agent-publish/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei @catee
|
||||
/frontend/packages/agent-ide/commons/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/arch/bot-api/ @Tecvan-fe
|
||||
/frontend/packages/arch/bot-http/ @Tecvan-fe
|
||||
/frontend/packages/arch/logger/ @Tecvan-fe
|
||||
/frontend/packages/arch/slardar-interface/ @Tecvan-fe @evan-crash
|
||||
/frontend/config/eslint-config/ @Tecvan-fe @leeight @soonco
|
||||
/frontend/infra/eslint-plugin/ @Tecvan-fe
|
||||
/frontend/config/ts-config/ @leeight @Tecvan-fe
|
||||
/frontend/config/vitest-config/ @Tecvan-fe
|
||||
/frontend/packages/arch/bot-env/ @Tecvan-fe @leeight
|
||||
/frontend/packages/arch/bot-env-adapter/ @dragooncjw @Tecvan-fe @leeight
|
||||
/frontend/packages/arch/bot-typings/ @Tecvan-fe
|
||||
/frontend/packages/arch/web-context/ @Tecvan-fe
|
||||
/frontend/packages/components/bot-semi/ @Tecvan-fe
|
||||
/frontend/packages/components/bot-icons/ @DingGao-Devin
|
||||
/frontend/packages/arch/i18n/ @Tecvan-fe @leeight
|
||||
/frontend/packages/arch/resources/studio-i18n-resource/ @dragooncjw @Tecvan-fe
|
||||
/frontend/config/stylelint-config/ @Tecvan-fe
|
||||
/frontend/packages/arch/idl/ @Tecvan-fe
|
||||
/frontend/infra/utils/fs-enhance/ @Tecvan-fe
|
||||
/frontend/packages/arch/bot-store/ @Tecvan-fe @catee @duwenhan2byte
|
||||
/frontend/packages/arch/bot-error/ @haozhenfei @duwenhan2byte
|
||||
/frontend/packages/foundation/space-store/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/arch/bot-flags/ @Tecvan-fe
|
||||
/frontend/packages/arch/report-events/ @Tecvan-fe
|
||||
/frontend/packages/foundation/enterprise-store-adapter/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/foundation/local-storage/ @duwenhan2byte @evan-crash
|
||||
/frontend/packages/foundation/space-store-adapter/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/arch/bot-tea/ @Tecvan-fe @catee @soonco
|
||||
/frontend/packages/arch/tea/ @Tecvan-fe @evan-crash @soonco
|
||||
/frontend/packages/arch/tea-adapter/ @dragooncjw @Tecvan-fe
|
||||
/frontend/packages/arch/tea-interface/ @dragooncjw @Tecvan-fe
|
||||
/frontend/packages/studio/stores/bot-detail/ @Hezi-crypto @catee @DingGao-Devin @duwenhan2byte @evan-crash
|
||||
/frontend/packages/agent-ide/bot-input-length-limit/ @Hezi-crypto @catee @duwenhan2byte
|
||||
/frontend/packages/agent-ide/tool-config/ @haozhenfei @catee
|
||||
/frontend/packages/arch/bot-space-api/ @Tecvan-fe @duwenhan2byte
|
||||
/frontend/packages/arch/bot-utils/ @Tecvan-fe
|
||||
/frontend/packages/common/uploader-adapter/ @dragooncjw @Tecvan-fe
|
||||
/frontend/packages/common/uploader-interface/ @dragooncjw @Tecvan-fe
|
||||
/frontend/packages/studio/user-store/ @duwenhan2byte @catee @lihuiwen
|
||||
/frontend/packages/arch/foundation-sdk/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/common/chat-area/chat-core/ @haozhenfei @Hezi-crypto @evan-crash
|
||||
/frontend/packages/common/chat-area/utils/ @Hezi-crypto @haozhenfei
|
||||
/frontend/packages/arch/bot-md-box-adapter/ @Hezi-crypto @iu1340 @dragooncjw @Tecvan-fe
|
||||
/frontend/packages/studio/common/file-kit/ @haozhenfei @evan-crash
|
||||
/frontend/packages/arch/slardar-adapter/ @Tecvan-fe @dragooncjw
|
||||
/frontend/packages/arch/default-slardar/ @Tecvan-fe @evan-crash
|
||||
/frontend/packages/arch/fetch-stream/ @Hezi-crypto @haozhenfei
|
||||
/frontend/packages/common/websocket-manager-adapter/ @haozhenfei @Hezi-crypto @catee
|
||||
/frontend/packages/studio/autosave/ @catee
|
||||
/frontend/packages/studio/bot-utils/ @catee @soonco @Hezi-crypto
|
||||
/frontend/packages/common/flowgram-adapter/common/ @zxhfighter @xiamidaxia @dragooncjw
|
||||
/frontend/packages/common/flowgram-adapter/free-layout-editor/ @zxhfighter @xiamidaxia @dragooncjw
|
||||
/frontend/packages/agent-ide/space-bot/ @soonco @evan-crash @duwenhan2byte @catee @DingGao-Devin
|
||||
/frontend/packages/agent-ide/space-bot/src/store/bot-list-filter/ @duwenhan2byte @lihuiwen
|
||||
/frontend/packages/agent-ide/space-bot/src/store/bot-page/ @DingGao-Devin
|
||||
/frontend/packages/agent-ide/space-bot/src/store/explore/ @Tecvan-fe
|
||||
/frontend/packages/agent-ide/space-bot/src/store/risk-warning/ @lihuiwen @catee
|
||||
/frontend/packages/agent-ide/context/ @evan-crash
|
||||
/frontend/packages/agent-ide/bot-editor-context-store/ @Hezi-crypto @duwenhan2byte @catee
|
||||
/frontend/packages/agent-ide/chat-background/ @catee
|
||||
/frontend/packages/agent-ide/chat-background-config-content-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/chat-background-config-content/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/chat-background-shared/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/common/chat-area/chat-uikit/ @catee @Hezi-crypto @evan-crash @haozhenfei
|
||||
/frontend/packages/common/chat-area/hooks/ @Hezi-crypto @evan-crash
|
||||
/frontend/packages/common/chat-area/chat-uikit-shared/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/bot-audit-adapter/ @evan-crash @duwenhan2byte @Hezi-crypto @haozhenfei
|
||||
/frontend/packages/agent-ide/bot-audit-base/ @evan-crash @duwenhan2byte @Hezi-crypto @haozhenfei
|
||||
/frontend/packages/studio/components/ @soonco @evan-crash @duwenhan2byte @catee
|
||||
/frontend/packages/arch/bot-hooks/ @catee @Tecvan-fe @soonco
|
||||
/frontend/packages/arch/bot-hooks/src/page-jump/ @evan-crash @catee
|
||||
/frontend/packages/arch/bot-hooks-adapter/ @catee @Tecvan-fe @soonco
|
||||
/frontend/packages/arch/bot-hooks-base/ @catee @Tecvan-fe @soonco
|
||||
/frontend/packages/arch/responsive-kit/ @Tecvan-fe @DingGao-Devin
|
||||
/frontend/packages/common/chat-area/chat-area/ @Hezi-crypto @haozhenfei @evan-crash @haozhenfei
|
||||
/frontend/packages/data/memory/llm-plugins/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/data/common/reporter/ @soonco @catee @evan-crash
|
||||
/frontend/packages/components/json-viewer/ @duwenhan2byte
|
||||
/frontend/packages/components/scroll-view/ @evan-crash
|
||||
/frontend/packages/common/assets/ @Tecvan-fe @catee
|
||||
/frontend/packages/common/biz-components/ @duwenhan2byte
|
||||
/frontend/packages/data/common/e2e/ @soonco @catee @evan-crash @haozhenfei @duwenhan2byte
|
||||
/frontend/packages/agent-ide/debug-tool-list/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/model-manager/ @Hezi-crypto @catee
|
||||
/frontend/packages/agent-ide/model-manager/src/components/multi-agent/ @catee
|
||||
/frontend/packages/agent-ide/tool/ @catee
|
||||
/frontend/packages/data/knowledge/knowledge-modal-base/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/components/biz-tooltip-ui/ @Hezi-crypto @catee @evan-crash
|
||||
/frontend/packages/components/table-view/ @lihuiwen
|
||||
/frontend/packages/components/virtual-list/ @Tecvan-fe
|
||||
/frontend/packages/data/common/utils/ @soonco @catee @evan-crash
|
||||
/frontend/packages/data/knowledge/knowledge-resource-processor-core/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/arch/pdfjs-shadow/ @Tecvan-fe
|
||||
/frontend/packages/data/knowledge/common/stores/ @soonco @catee @evan-crash
|
||||
/frontend/packages/foundation/global-store/ @duwenhan2byte @evan-crash
|
||||
/frontend/config/postcss-config/ @Tecvan-fe
|
||||
/frontend/config/tailwind-config/ @Tecvan-fe
|
||||
/frontend/infra/utils/monorepo-kits/ @Tecvan-fe @evan-crash
|
||||
/frontend/packages/studio/premium/premium-components-adapter/ @evan-crash
|
||||
/frontend/packages/studio/premium/premium-store-adapter/ @evan-crash
|
||||
/frontend/packages/agent-ide/onboarding/ @Hezi-crypto @catee
|
||||
/frontend/packages/agent-ide/publish-to-base/ @catee
|
||||
/frontend/packages/arch/report-tti/ @duwenhan2byte
|
||||
/frontend/packages/data/memory/database-creator/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/arch/hooks/ @Tecvan-fe @evan-crash
|
||||
/frontend/packages/common/coze-mitt/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/common/editor-plugins/ @haozhenfei @stream-pipe @Hezi-crypto
|
||||
/frontend/packages/common/md-editor-adapter/ @haozhenfei @Hezi-crypto @catee
|
||||
/frontend/packages/common/prompt-kit/main/ @haozhenfei @Hezi-crypto @catee
|
||||
/frontend/packages/common/chat-area/chat-answer-action/ @Hezi-crypto @haozhenfei @lihuiwen
|
||||
/frontend/packages/common/chat-area/plugin-message-grab/ @Hezi-crypto @haozhenfei
|
||||
/frontend/packages/common/chat-area/text-grab/ @Hezi-crypto @haozhenfei
|
||||
/frontend/packages/common/prompt-kit/adapter/ @haozhenfei @Hezi-crypto @catee
|
||||
/frontend/packages/common/prompt-kit/base/ @haozhenfei @Hezi-crypto @catee
|
||||
/frontend/packages/data/memory/database/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/data/knowledge/knowledge-resource-processor-base/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/arch/utils/ @Tecvan-fe @evan-crash
|
||||
/frontend/packages/data/knowledge/common/components/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/data/common/feature-register/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/data/knowledge/common/hooks/ @Hezi-crypto @catee @evan-crash
|
||||
/frontend/packages/data/knowledge/common/services/ @Hezi-crypto @catee @evan-crash
|
||||
/frontend/packages/data/memory/database-v2-main/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/data/memory/database-v2-adapter/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/data/memory/database-v2-base/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/data/knowledge/knowledge-data-set-for-agent/ @Hezi-crypto @catee @evan-crash
|
||||
/frontend/packages/data/knowledge/knowledge-ide-base/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/arch/bot-monaco-editor/ @Tecvan-fe
|
||||
/frontend/packages/data/knowledge/knowledge-modal-adapter/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/data/knowledge/knowledge-resource-processor-adapter/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/devops/debug/debug-panel/ @soonco @evan-crash @catee
|
||||
/frontend/packages/devops/json-link-preview/ @Maidang1 @Zhangchi123456
|
||||
/frontend/packages/devops/common-modules/ @duwenhan2byte @evan-crash @catee
|
||||
/frontend/packages/foundation/account-adapter/ @duwenhan2byte @evan-crash
|
||||
/frontend/packages/foundation/account-base/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/arch/api-schema/ @Tecvan-fe @evan-crash
|
||||
/frontend/infra/idl/idl2ts-runtime/ @Tecvan-fe @evan-crash
|
||||
/frontend/infra/idl/idl2ts-cli/ @Tecvan-fe @evan-crash
|
||||
/frontend/infra/idl/idl2ts-generator/ @Tecvan-fe @evan-crash
|
||||
/frontend/infra/idl/idl-parser/ @Tecvan-fe @evan-crash
|
||||
/frontend/infra/utils/rush-logger/ @catee @Tecvan-fe
|
||||
/frontend/infra/idl/idl2ts-helper/ @Tecvan-fe @evan-crash
|
||||
/frontend/infra/idl/idl2ts-plugin/ @Tecvan-fe @evan-crash
|
||||
/frontend/packages/studio/open-platform/open-env-adapter/ @soonco @Hezi-crypto @DingGao-Devin
|
||||
/frontend/infra/plugins/pkg-root-webpack-plugin/ @Tecvan-fe
|
||||
/frontend/packages/studio/publish-manage-hooks/ @duwenhan2byte @evan-crash
|
||||
/frontend/packages/foundation/layout/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/studio/open-platform/open-auth/ @evan-crash @DingGao-Devin
|
||||
/frontend/packages/studio/open-platform/open-chat/ @tomasyu985 @DingGao-Devin
|
||||
/frontend/packages/agent-ide/entry-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/entry/ @soonco @duwenhan2byte @catee @evan-crash
|
||||
/frontend/packages/agent-ide/bot-config-area-adapter/ @haozhenfei @Hezi-crypto @duwenhan2byte @catee @evan-crash
|
||||
/frontend/packages/agent-ide/bot-config-area/ @haozhenfei @Hezi-crypto @duwenhan2byte @catee @evan-crash
|
||||
/frontend/packages/agent-ide/bot-plugin/entry/ @evan-crash @lihuiwen @catee
|
||||
/frontend/packages/agent-ide/bot-plugin/export/ @lihuiwen @catee
|
||||
/frontend/packages/agent-ide/bot-plugin/mock-set/ @lihuiwen @catee @duwenhan2byte
|
||||
/frontend/packages/studio/mockset-edit-modal-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/studio/mockset-shared/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/studio/mockset-editor/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/studio/mockset-editor-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/bot-plugin/tools/ @lihuiwen @catee
|
||||
/frontend/packages/studio/stores/bot-plugin/ @lihuiwen @Hezi-crypto @catee
|
||||
/frontend/packages/studio/plugin-shared/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/plugin-modal-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/plugin-shared/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/community/component/ @DingGao-Devin @Hezi-crypto @evan-crash @duwenhan2byte
|
||||
/frontend/packages/studio/plugin-form-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/workflow/base/ @xiamidaxia @zxhfighter
|
||||
/frontend/packages/agent-ide/plugin-content-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/plugin-content/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/plugin-setting-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/plugin-setting/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/bot-plugin/plugin-risk-warning/ @catee @evan-crash
|
||||
/frontend/packages/studio/plugin-publish-ui-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/studio/plugin-tool-columns-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/studio/plugin-tool-columns/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/chat-debug-area/ @soonco @duwenhan2byte @catee @Hezi-crypto @haozhenfei @evan-crash
|
||||
/frontend/packages/agent-ide/chat-answer-action-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/chat-area-plugin-debug-common/ @Hezi-crypto @haozhenfei
|
||||
/frontend/packages/agent-ide/chat-components-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/common/chat-area/plugin-chat-background/ @Tecvan-fe
|
||||
/frontend/packages/common/chat-area/chat-area-plugin-reasoning/ @catee @Hezi-crypto
|
||||
/frontend/packages/common/chat-area/plugin-resume/ @Tecvan-fe
|
||||
/frontend/packages/common/chat-area/plugin-chat-shortcuts/ @haozhenfei @duwenhan2byte @Hezi-crypto
|
||||
/frontend/packages/workflow/sdk/ @zxhfighter @xiamidaxia
|
||||
/frontend/packages/workflow/components/ @LLLLeeJ @zxhfighter
|
||||
/frontend/packages/components/loading-button/ @catee
|
||||
/frontend/packages/components/mouse-pad-selector/ @zxhfighter
|
||||
/frontend/packages/workflow/adapter/resources/ @LLLLeeJ @JxJuly @xiamidaxia @luics @zxhfighter @stream-pipe
|
||||
/frontend/packages/common/chat-area/chat-workflow-render/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/onboarding-message-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/plugin-area-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/prompt-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/prompt/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/workflow/ @soonco @duwenhan2byte @catee
|
||||
/frontend/packages/agent-ide/navigate/ @soonco @duwenhan2byte @catee
|
||||
/frontend/packages/agent-ide/workflow-as-agent-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/workflow-item/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/workflow-card-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/workflow-modal/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/memory-tool-pane-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/skills-pane-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/layout-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/layout/ @soonco @duwenhan2byte @catee
|
||||
/frontend/packages/agent-ide/chat-area-provider-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/chat-area-provider/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/studio/entity-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/foundation/account-ui-adapter/ @duwenhan2byte @evan-crash
|
||||
/frontend/packages/foundation/account-ui-base/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/foundation/foundation-sdk/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/foundation/global/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/studio/workspace/project-entity-adapter/ @Hezi-crypto @catee @duwenhan2byte
|
||||
/frontend/packages/studio/workspace/project-entity-base/ @Hezi-crypto @catee @duwenhan2byte
|
||||
/frontend/packages/foundation/global-adapter/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/foundation/browser-upgrade-banner/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/foundation/space-ui-adapter/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/foundation/space-ui-base/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/common/auth/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/common/auth-adapter/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/project-ide/main/ @dragooncjw @JxJuly @xiamidaxia @catee @lihuiwen
|
||||
/frontend/packages/components/resource-tree/ @dragooncjw @xiamidaxia @JxJuly
|
||||
/frontend/packages/common/flowgram-adapter/fixed-layout-editor/ @zxhfighter @xiamidaxia @dragooncjw
|
||||
/frontend/packages/project-ide/biz-components/ @zxhfighter @xiamidaxia
|
||||
/frontend/packages/project-ide/framework/ @dragooncjw @JxJuly @xiamidaxia
|
||||
/frontend/packages/project-ide/base-adapter/ @dragooncjw @xiamidaxia
|
||||
/frontend/packages/project-ide/base-interface/ @dragooncjw @xiamidaxia
|
||||
/frontend/packages/project-ide/client/ @dragooncjw @JxJuly @xiamidaxia
|
||||
/frontend/packages/project-ide/core/ @dragooncjw @JxJuly @xiamidaxia
|
||||
/frontend/packages/project-ide/view/ @dragooncjw @JxJuly @xiamidaxia
|
||||
/frontend/packages/project-ide/biz-data/ @haozhenfei @lihuiwen @catee @soonco
|
||||
/frontend/packages/data/knowledge/knowledge-ide-adapter/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/data/memory/variables/ @haozhenfei @catee @Hezi-crypto
|
||||
/frontend/packages/project-ide/biz-plugin/ @xiamidaxia @lihuiwen @catee
|
||||
/frontend/packages/project-ide/biz-plugin-registry-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/project-ide/biz-workflow/ @dragooncjw @JxJuly @xiamidaxia
|
||||
/frontend/packages/studio/open-platform/open-chat/ @soonco @Hezi-crypto @DingGao-Devin
|
||||
/frontend/packages/workflow/playground/ @LLLLeeJ @xiamidaxia @luics @zxhfighter
|
||||
/frontend/packages/arch/load-remote-worker/ @Tecvan-fe
|
||||
/frontend/packages/devops/mockset-manage/ @soonco @evan-crash @catee
|
||||
/frontend/packages/devops/testset-manage/ @mocayo @JxJuly
|
||||
/frontend/packages/workflow/adapter/base/ @LLLLeeJ @JxJuly @xiamidaxia @luics @zxhfighter @stream-pipe
|
||||
/frontend/packages/workflow/adapter/code-editor/ @LLLLeeJ @JxJuly @xiamidaxia @luics @zxhfighter @stream-pipe
|
||||
/frontend/packages/workflow/fabric-canvas/ @xiamidaxia @zxhfighter
|
||||
/frontend/packages/workflow/feature-encapsulate/ @zxhfighter
|
||||
/frontend/packages/workflow/nodes/ @xiamidaxia @zxhfighter
|
||||
/frontend/packages/workflow/setters/ @Tecvan-fe
|
||||
/frontend/packages/workflow/variable/ @zxhfighter @LLLLeeJ @xiamidaxia
|
||||
/frontend/packages/workflow/render/ @dragooncjw @xiamidaxia
|
||||
/frontend/packages/workflow/history/ @xiamidaxia @zxhfighter
|
||||
/frontend/packages/workflow/adapter/nodes/ @LLLLeeJ @JxJuly @xiamidaxia @luics @zxhfighter @stream-pipe
|
||||
/frontend/packages/workflow/test-run/ @JxJuly @xiamidaxia @luics @zxhfighter @dragooncjw
|
||||
/frontend/packages/workflow/test-run-next/main/ @JxJuly @LLLLeeJ @xiamidaxia @zxhfighter
|
||||
/frontend/packages/workflow/test-run-next/form/ @JxJuly @LLLLeeJ @xiamidaxia @zxhfighter
|
||||
/frontend/packages/workflow/test-run-next/shared/ @JxJuly @LLLLeeJ @xiamidaxia @zxhfighter
|
||||
/frontend/packages/workflow/test-run-next/trace/ @JxJuly @LLLLeeJ @xiamidaxia @zxhfighter
|
||||
/frontend/packages/project-ide/ui-adapter/ @dragooncjw @xiamidaxia
|
||||
/frontend/packages/studio/workspace/project-publish/ @catee @lihuiwen
|
||||
/frontend/packages/studio/workspace/entry-adapter/ @duwenhan2byte @evan-crash
|
||||
/frontend/packages/studio/workspace/entry-base/ @duwenhan2byte @catee @evan-crash
|
||||
/frontend/packages/workflow/adapter/playground/ @LLLLeeJ @JxJuly @xiamidaxia @luics @zxhfighter @stream-pipe
|
||||
/frontend/infra/plugins/import-watch-loader/ @Tecvan-fe
|
||||
/frontend/config/rsbuild-config/ @Tecvan-fe
|
||||
/frontend/packages/community/explore/ @evan-crash @duwenhan2byte
|
||||
/frontend/common/_templates/node-core/ @Tecvan-fe
|
||||
/frontend/common/_templates/rspack-web/ @Tecvan-fe
|
||||
|
||||
|
||||
/backend/ @fanlv @junwen-lee @liuyunchao-1998 @lvxinyu-1117 @hi-pender @luohq-bytedance @shentongmartin @mrh997 @meguminnnnnnnnn @N3kox @zhuangjie1125
|
||||
/docker/ @fanlv @junwen-lee @liuyunchao-1998 @lvxinyu-1117 @hi-pender @luohq-bytedance @shentongmartin @mrh997 @meguminnnnnnnnn @N3kox @zhuangjie1125
|
||||
/helm/ @fanlv @junwen-lee @liuyunchao-1998 @lvxinyu-1117 @hi-pender @luohq-bytedance @shentongmartin @mrh997 @meguminnnnnnnnn @N3kox @zhuangjie1125
|
||||
294
.github/workflows/ci.yml
vendored
Normal file
294
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,294 @@
|
||||
name: CI
|
||||
on:
|
||||
pull_request:
|
||||
branches: ['main']
|
||||
paths:
|
||||
- 'github/**'
|
||||
- 'idl/**'
|
||||
- 'frontend/**'
|
||||
- 'common/**'
|
||||
- 'rush.json'
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- NodeVersion: 22.16.0
|
||||
NodeVersionDisplayName: 22
|
||||
OS: ubuntu-latest
|
||||
name: Setup and Install Dependencies
|
||||
runs-on: ${{ matrix.OS }}
|
||||
outputs:
|
||||
cache_file: ${{ steps.process-files.outputs.cache_file }}
|
||||
matrix_node_version: ${{ matrix.NodeVersion }}
|
||||
matrix_os: ${{ matrix.OS }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v45
|
||||
|
||||
- name: Process changed files
|
||||
id: process-files
|
||||
run: |
|
||||
# 获取所有变更文件
|
||||
all_files="${{ steps.changed-files.outputs.all_changed_files }}"
|
||||
|
||||
# 过滤掉 common/changes 目录下的文件
|
||||
filtered_files=""
|
||||
for file in $all_files; do
|
||||
if [[ ! "$file" =~ ^common/changes/.* ]]; then
|
||||
if [ -z "$filtered_files" ]; then
|
||||
filtered_files="$file"
|
||||
else
|
||||
filtered_files="$filtered_files $file"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 创建 JSON 格式的缓存文件
|
||||
echo "[$( echo "$filtered_files" | sed 's/ /", "/g' | sed 's/^/"/' | sed 's/$/"/' )]" > changed-files-cache.json
|
||||
|
||||
# 输出缓存文件路径供后续步骤使用
|
||||
echo "cache_file=changed-files-cache.json" >> $GITHUB_OUTPUT
|
||||
|
||||
echo "过滤前文件数量: $(echo $all_files | wc -w)"
|
||||
echo "过滤后文件数量: $(echo $filtered_files | wc -w)"
|
||||
echo "已生成缓存文件: changed-files-cache.json"
|
||||
|
||||
- name: Config Git User
|
||||
# should be turn to ci user
|
||||
run: |
|
||||
git config --local user.name "flow_bot"
|
||||
git config --local user.email "flow_bot@bytedance.com"
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.NodeVersion }}
|
||||
|
||||
- name: Upload changed files cache
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: changed-files-cache
|
||||
path: changed-files-cache.json
|
||||
retention-days: 1
|
||||
|
||||
build:
|
||||
needs: setup
|
||||
runs-on: ${{ needs.setup.outputs.matrix_os }}
|
||||
name: Increment Build
|
||||
env:
|
||||
BUILD_BRANCH: ${{ github.head_ref || github.ref_name }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ needs.setup.outputs.matrix_node_version }}
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
common/temp/pnpm-local
|
||||
common/temp/pnpm-store
|
||||
common/temp/install-run
|
||||
key: ${{ runner.os }}-rush-store-${{ hashFiles('common/config/subspaces/**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-rush-store-main
|
||||
${{ runner.os }}-rush-store
|
||||
|
||||
- name: Download changed files cache
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: changed-files-cache
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libasound2-dev
|
||||
node common/scripts/install-run-rush.js install --to tag:core
|
||||
node common/scripts/install-run-rush.js update-autoinstaller --name plugins
|
||||
node common/scripts/install-run-rush.js increment --action install -p "${{ needs.setup.outputs.cache_file }}"
|
||||
|
||||
- name: Increment Build
|
||||
run: node common/scripts/install-run-rush.js increment --action build -p "${{ needs.setup.outputs.cache_file }}"
|
||||
|
||||
test:
|
||||
needs: setup
|
||||
runs-on: ${{ needs.setup.outputs.matrix_os }}
|
||||
name: Increment Test Coverage
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ needs.setup.outputs.matrix_node_version }}
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
common/temp/pnpm-local
|
||||
common/temp/pnpm-store
|
||||
common/temp/install-run
|
||||
key: ${{ runner.os }}-rush-store-${{ hashFiles('common/config/subspaces/**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-rush-store-main
|
||||
${{ runner.os }}-rush-store
|
||||
|
||||
- name: Download changed files cache
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: changed-files-cache
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libasound2-dev
|
||||
node common/scripts/install-run-rush.js install --to tag:core
|
||||
node common/scripts/install-run-rush.js update-autoinstaller --name plugins
|
||||
node common/scripts/install-run-rush.js increment --action install -p "${{ needs.setup.outputs.cache_file }}"
|
||||
|
||||
- name: Increment Test:cov
|
||||
run: node common/scripts/install-run-rush.js increment --action test:cov -p "${{ needs.setup.outputs.cache_file }}"
|
||||
|
||||
- name: Upload coverage reports
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
|
||||
lint:
|
||||
needs: setup
|
||||
runs-on: ${{ needs.setup.outputs.matrix_os }}
|
||||
name: Increment Lint
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ needs.setup.outputs.matrix_node_version }}
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
common/temp/pnpm-local
|
||||
common/temp/pnpm-store
|
||||
common/temp/install-run
|
||||
key: ${{ runner.os }}-rush-store-${{ hashFiles('common/config/subspaces/**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-rush-store-main
|
||||
${{ runner.os }}-rush-store
|
||||
|
||||
- name: Download changed files cache
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: changed-files-cache
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libasound2-dev
|
||||
node common/scripts/install-run-rush.js install --to tag:core
|
||||
node common/scripts/install-run-rush.js update-autoinstaller --name plugins
|
||||
node common/scripts/install-run-rush.js increment --action install -p "${{ needs.setup.outputs.cache_file }}"
|
||||
|
||||
- name: Increment Lint
|
||||
run: node common/scripts/install-run-rush.js increment --action lint -p "${{ needs.setup.outputs.cache_file }}"
|
||||
|
||||
ts-check:
|
||||
needs: setup
|
||||
runs-on: ${{ needs.setup.outputs.matrix_os }}
|
||||
name: Increment TS Check
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ needs.setup.outputs.matrix_node_version }}
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
common/temp/pnpm-local
|
||||
common/temp/pnpm-store
|
||||
common/temp/install-run
|
||||
key: ${{ runner.os }}-rush-store-${{ hashFiles('common/config/subspaces/**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-rush-store-main
|
||||
${{ runner.os }}-rush-store
|
||||
|
||||
- name: Download changed files cache
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: changed-files-cache
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libasound2-dev
|
||||
node common/scripts/install-run-rush.js install --to tag:core
|
||||
node common/scripts/install-run-rush.js update-autoinstaller --name plugins
|
||||
node common/scripts/install-run-rush.js increment --action install -p "${{ needs.setup.outputs.cache_file }}"
|
||||
|
||||
- name: Increment TS Check
|
||||
run: node common/scripts/install-run-rush.js increment --action ts-check -p "${{ needs.setup.outputs.cache_file }}"
|
||||
|
||||
package-audit:
|
||||
needs: setup
|
||||
runs-on: ${{ needs.setup.outputs.matrix_os }}
|
||||
name: Increment Package Audit
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ needs.setup.outputs.matrix_node_version }}
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
common/temp/pnpm-local
|
||||
common/temp/pnpm-store
|
||||
common/temp/install-run
|
||||
key: ${{ runner.os }}-rush-store-${{ hashFiles('common/config/subspaces/**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-rush-store-main
|
||||
${{ runner.os }}-rush-store
|
||||
|
||||
- name: Download changed files cache
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: changed-files-cache
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libasound2-dev
|
||||
node common/scripts/install-run-rush.js install --to tag:core
|
||||
node common/scripts/install-run-rush.js update-autoinstaller --name plugins
|
||||
node common/scripts/install-run-rush.js increment --action install -p "${{ needs.setup.outputs.cache_file }}"
|
||||
|
||||
- name: Increment Package Audit
|
||||
run: node common/scripts/install-run-rush.js increment --action package-audit -p "${{ needs.setup.outputs.cache_file }}"
|
||||
72
.github/workflows/ci@main.yml
vendored
Normal file
72
.github/workflows/ci@main.yml
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
# should be optimize as increment build & test
|
||||
name: CI@main
|
||||
on:
|
||||
push:
|
||||
# test only
|
||||
branches: ['main',"chore/setup-ci"]
|
||||
paths:
|
||||
- 'github/**'
|
||||
- 'idl/**'
|
||||
- 'frontend/**'
|
||||
- 'common/**'
|
||||
- 'rush.json'
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- NodeVersion: 22.16.0
|
||||
NodeVersionDisplayName: 22
|
||||
OS: ubuntu-latest
|
||||
name: Node.js v${{ matrix.NodeVersionDisplayName }} (${{ matrix.OS }})
|
||||
runs-on: ${{ matrix.OS }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Config Git User
|
||||
# should be turn to ci user
|
||||
run: |
|
||||
git config --local user.name "flow_bot"
|
||||
git config --local user.email "flow_bot@bytedance.com"
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.NodeVersion }}
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
common/temp/pnpm-local
|
||||
common/temp/pnpm-store
|
||||
common/temp/install-run
|
||||
key: ${{ runner.os }}-rush-store-main
|
||||
restore-keys: |
|
||||
${{ runner.os }}-rush-store-main
|
||||
${{ runner.os }}-rush-store
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libasound2-dev
|
||||
node common/scripts/install-run-rush.js install
|
||||
|
||||
- name: Build all
|
||||
run: node common/scripts/install-run-rush.js build --verbose
|
||||
|
||||
- name: Test:cov all
|
||||
run: node common/scripts/install-run-rush.js test:cov --verbose
|
||||
|
||||
- name: Upload coverage reports
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
|
||||
- name: Lint all
|
||||
run: node common/scripts/install-run-rush.js lint --verbose
|
||||
45
.github/workflows/common-pr-checks.yml
vendored
Normal file
45
.github/workflows/common-pr-checks.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
name: PR Common Checks
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'github/**'
|
||||
- 'idl/**'
|
||||
- 'frontend/**'
|
||||
- 'common/**'
|
||||
- 'rush.json'
|
||||
types: [opened, edited, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
common-checks:
|
||||
name: PR Common Checks
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Config Git User
|
||||
run: |
|
||||
git config --local user.name "flow_bot"
|
||||
git config --local user.email "flow_bot@bytedance.com"
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 22.16.0
|
||||
|
||||
- name: Install Dependencies
|
||||
run: node common/scripts/install-run-rush.js install
|
||||
|
||||
# PR Title Format Check
|
||||
- name: Check PR Title Format
|
||||
if: ${{ !contains(github.event.pull_request.title, 'WIP') && !contains(github.event.pull_request.title, 'wip') }}
|
||||
env:
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
run: |
|
||||
node common/scripts/install-run-rush.js update-autoinstaller --name rush-commitlint && \
|
||||
pushd common/autoinstallers/rush-commitlint && \
|
||||
echo "$PR_TITLE" | npx commitlint --config commitlint.config.js && \
|
||||
popd
|
||||
|
||||
# Add more common checks here
|
||||
# For example: file size checks, specific file format validations, etc.
|
||||
2
AUTHORS
2
AUTHORS
@ -44,3 +44,5 @@ lingyibin.jason <lingyibin.jason@bytedance.com>
|
||||
chenchen.dabaishu <chenchen.dabaishu@bytedance.com>
|
||||
jiangxujin <jiangxujin@bytedance.com>
|
||||
huyongbiao <huyongbiao@bytedance.com>
|
||||
wenming.2020 <wenming.2020@bytedance.com>
|
||||
tanjizhen <tanjizhen@bytedance.com>
|
||||
|
||||
@ -28,7 +28,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
3. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the coze-dev {project_name} repo.
|
||||
4. In your forked repository, make your changes in a new git branch:
|
||||
```
|
||||
git checkout -b my-fix-branch develop
|
||||
git checkout -b my-fix-branch main
|
||||
```
|
||||
5. Create your patch, including appropriate test cases.
|
||||
6. Follow our [Style Guides](#code-style-guides).
|
||||
@ -38,7 +38,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
```
|
||||
git push origin my-fix-branch
|
||||
```
|
||||
9. In GitHub, send a pull request to `{project_name}:develop`
|
||||
9. In GitHub, send a pull request to `{project_name}:main`
|
||||
|
||||
## Contribution Prerequisites
|
||||
- Our development environment keeps up with [Go Official](https://golang.org/project/).
|
||||
|
||||
10
Makefile
10
Makefile
@ -13,6 +13,8 @@ MYSQL_SCHEMA := ./docker/volumes/mysql/schema.sql
|
||||
MYSQL_INIT_SQL := ./docker/volumes/mysql/sql_init.sql
|
||||
ENV_FILE := ./docker/.env
|
||||
STATIC_DIR := ./bin/resources/static
|
||||
ES_INDEX_SCHEMA := ./docker/volumes/elasticsearch/es_index_schema
|
||||
ES_SETUP_SCRIPT := ./docker/volumes/elasticsearch/setup_es.sh
|
||||
|
||||
debug: env middleware python server
|
||||
|
||||
@ -26,7 +28,7 @@ fe:
|
||||
@echo "Building frontend..."
|
||||
@bash $(BUILD_FE_SCRIPT)
|
||||
|
||||
server: env
|
||||
server: env setup_es_index
|
||||
@if [ ! -d "$(STATIC_DIR)" ]; then \
|
||||
echo "Static directory '$(STATIC_DIR)' not found, building frontend..."; \
|
||||
$(MAKE) fe; \
|
||||
@ -84,6 +86,11 @@ atlas-hash:
|
||||
@echo "Rehash atlas migration files..."
|
||||
@(cd ./docker/atlas && atlas migrate hash)
|
||||
|
||||
setup_es_index:
|
||||
@echo "Setting up Elasticsearch index..."
|
||||
@. $(ENV_FILE); \
|
||||
bash $(ES_SETUP_SCRIPT) --index-dir $(ES_INDEX_SCHEMA) --docker-host false --es-address "$$ES_ADDR"
|
||||
|
||||
help:
|
||||
@echo "Usage: make [target]"
|
||||
@echo ""
|
||||
@ -103,4 +110,5 @@ help:
|
||||
@echo " clean - Stop the docker containers and clean volumes."
|
||||
@echo " python - Setup python environment."
|
||||
@echo " atlas-hash - Rehash atlas migration files."
|
||||
@echo " setup_es_index - Setup elasticsearch index."
|
||||
@echo " help - Show this help message."
|
||||
|
||||
32
README.md
32
README.md
@ -72,8 +72,9 @@ Deployment steps:
|
||||
# Start the service
|
||||
cd docker
|
||||
cp .env.example .env
|
||||
docker compose --profile '*' up -d
|
||||
docker compose --profile "*" up -d
|
||||
```
|
||||
After the service starts, it is normal for the `coze-minio-setup` , `coze-mysql-setup-init-sql` , and `coze-mysql-setup-schema` containers to be in an exited state (exit 0). For common startup failure issues, **please refer to the [FAQ](https://github.com/coze-dev/coze-studio/wiki/9.-FAQ)**.
|
||||
4. After starting the service, you can open Coze Studio by accessing `http://localhost:8888/` through your browser.
|
||||
|
||||
|
||||
@ -83,7 +84,7 @@ Deployment steps:
|
||||
* [Model Configuration](https://github.com/coze-dev/coze-studio/wiki/3.-Model-configuration): Before deploying the open-source version of Coze Studio, you must configure the model service. Otherwise, you cannot select models when building agents, workflows, and apps.
|
||||
* [Plugin Configuration](https://github.com/coze-dev/coze-studio/wiki/4.-Plugin-Configuration): To use official plugins from the plugin store, you must first configure the plugins and add the authentication keys for third-party services.
|
||||
* [Basic Component Configuration](https://github.com/coze-dev/coze-studio/wiki/5.-Basic-component-configuration): Learn how to configure components such as image uploaders to use functions like image uploading in Coze Studio .
|
||||
* [API Reference](https://github.com/coze-dev/coze-studio/wiki/6.-API-Reference): Unlike the commercial edition, the open-source version of Coze Studio only supports personal access token (PAT) authentication and supports APIs related to chat and workflows.
|
||||
* [API Reference](https://github.com/coze-dev/coze-studio/wiki/6.-API-Reference): The Coze Studio Community Edition API and Chat SDK are authenticated using Personal Access Token, providing APIs for conversations and workflows.
|
||||
* [Development Guidelines](https://github.com/coze-dev/coze-studio/wiki/7.-Development-Standards):
|
||||
* [Project Architecture](https://github.com/coze-dev/coze-studio/wiki/7.-Development-Standards#project-architecture): Learn about the technical architecture and core components of the open-source version of Coze Studio.
|
||||
* [Code Development and Testing](https://github.com/coze-dev/coze-studio/wiki/7.-Development-Standards#code-development-and-testing): Learn how to perform secondary development and testing based on the open-source version of Coze Studio.
|
||||
@ -107,14 +108,33 @@ We welcome community contributions. For contribution guidelines, please refer to
|
||||
## Security and privacy
|
||||
If you discover potential security issues in the project, or believe you may have found a security issue, please notify the ByteDance security team through our [security center](https://security.bytedance.com/src) or [vulnerability reporting mailbox](https://code.byted.org/flowdevops/cozeloop/blob/feat/release/sec@bytedance.com).
|
||||
Please **do not** create public GitHub Issues.
|
||||
## Join the community
|
||||
Scan the QR code below using the Lark mobile app to join the Coze Studio technical exchange group.
|
||||
## Join Community
|
||||
|
||||
We are committed to building an open and friendly developer community. All developers interested in AI Agent development are welcome to join us!
|
||||
|
||||
### 🐛 Issue Reports & Feature Requests
|
||||
To efficiently track and resolve issues while ensuring transparency and collaboration, we recommend participating through:
|
||||
- **GitHub Issues**: [Submit bug reports or feature requests](https://github.com/coze-dev/coze-studio/issues)
|
||||
- **Pull Requests**: [Contribute code or documentation improvements](https://github.com/coze-dev/coze-studio/pulls)
|
||||
|
||||
### 💬 Technical Discussion & Communication
|
||||
Join our technical discussion groups to share experiences with other developers and stay updated with the latest project developments:
|
||||
|
||||
**Feishu Group Chat**
|
||||
Scan the QR code below with Feishu mobile app to join:
|
||||
|
||||

|
||||
|
||||
**Discord Server**
|
||||
Click to join: [Coze Community](https://discord.gg/sTVN9EVS4B)
|
||||
|
||||
**Telegram Group**
|
||||
Click to join: Telegram Group [Coze](https://t.me/+pP9CkPnomDA0Mjgx)
|
||||
|
||||
## Acknowledgments
|
||||
Thank you to all the developers and community members who have contributed to the Coze Studio project. Special thanks:
|
||||
|
||||
* LLM integration support provided by the Eino framework team
|
||||
* High-performance framework developed by the Cloudwego team
|
||||
* The [Eino](https://github.com/cloudwego/eino) framework team - providing powerful support for Coze Studio's agent and workflow runtime engines, model abstractions and implementations, and knowledge base indexing and retrieval
|
||||
* The [FlowGram](https://github.com/bytedance/flowgram.ai) team - providing a high-quality workflow building engine for Coze Studio's frontend workflow canvas editor
|
||||
* The [Hertz](https://github.com/cloudwego/hertz) team - Go HTTP framework with high-performance and strong-extensibility for building micro-services
|
||||
* All users who participated in testing and feedback
|
||||
@ -25,6 +25,7 @@
|
||||
Coze Studio,源自服务了上万家企业、数百万开发者的「扣子开发平台」,我们将它的核心引擎完全开放。它是一个一站式的 AI Agent 可视化开发工具,让 AI Agent 的创建、调试和部署变得前所未有的简单。通过 Coze Studio 提供的可视化设计与编排工具,开发者可以通过零代码或低代码的方式,快速打造和调试智能体、应用和工作流,实现强大的 AI 应用开发和更多定制化业务逻辑,是构建低代码 AI 产品的理想选择。Coze Studio 致力于降低 AI Agent 开发与应用门槛,鼓励社区共建和分享交流,助你在 AI 领域进行更深层次的探索与实践。
|
||||
|
||||
Coze Studio 的后端采用 Golang 开发,前端使用 React + TypeScript,整体基于微服务架构并遵循领域驱动设计(DDD)原则构建。为开发者提供一个高性能、高扩展性、易于二次开发的底层框架,助力开发者应对复杂的业务需求。
|
||||
|
||||
## 功能清单
|
||||
| **功能模块** | **功能点** |
|
||||
| --- | --- |
|
||||
@ -71,8 +72,10 @@ Coze Studio 的后端采用 Golang 开发,前端使用 React + TypeScript,
|
||||
# 启动服务
|
||||
cd docker
|
||||
cp .env.example .env
|
||||
docker compose --profile '*' up -d
|
||||
docker compose --profile "*" up -d
|
||||
```
|
||||
服务启动之后`coze-minio-setup`、`coze-mysql-setup-init-sql`、`coze-mysql-setup-schema` 这几个容器处于退出状态(exit 0),是正常现象。**启动失败常见问题可参考[常见问题](https://github.com/coze-dev/coze-studio/wiki/9.-%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)**。
|
||||
|
||||
4. 启动服务后,通过浏览器访问 `http://localhost:8888/` 即可打开 Coze Studio。
|
||||
|
||||
## 开发指南
|
||||
@ -81,7 +84,7 @@ Coze Studio 的后端采用 Golang 开发,前端使用 React + TypeScript,
|
||||
* [模型配置](https://github.com/coze-dev/coze-studio/wiki/3.-模型配置):部署 Coze Studio 开源版之前,必须配置模型服务,否则无法在搭建智能体、工作流和应用时选择模型。
|
||||
* [插件配置](https://github.com/coze-dev/coze-studio/wiki/4.-插件配置):如需使用插件商店中的官方插件,必须先配置插件,添加第三方服务的鉴权秘钥。
|
||||
* [基础组件配置](https://github.com/coze-dev/coze-studio/wiki/5.-基础组件配置):了解如何配置图片上传等组件,以便在 Coze Studio 中使用上传图片等功能。
|
||||
* [API 参考](https://github.com/coze-dev/coze-studio/wiki/6.-API-参考):和商业版不同,Coze Studio 开源版仅支持个人访问秘钥(PAT)鉴权,并支持对话和工作流相关 API。
|
||||
* [API 参考](https://github.com/coze-dev/coze-studio/wiki/6.-API-参考):Coze Studio 社区版 API 和 Chat SDK 通过个人访问令牌鉴权,提供对话和工作流相关 API。
|
||||
* [开发规范](https://github.com/coze-dev/coze-studio/wiki/7.-开发规范):
|
||||
* [项目架构](https://github.com/coze-dev/coze-studio/wiki/7.-%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83#%E9%A1%B9%E7%9B%AE%E6%9E%B6%E6%9E%84):了解 Coze Studio 开源版的技术架构与核心组件。
|
||||
* [代码开发与测试](https://github.com/coze-dev/coze-studio/wiki/7.-%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83#%E4%BB%A3%E7%A0%81%E5%BC%80%E5%8F%91%E4%B8%8E%E6%B5%8B%E8%AF%95):了解如何基于 Coze Studio 开源版进行二次开发与测试。
|
||||
@ -106,13 +109,32 @@ Coze Studio 的后端采用 Golang 开发,前端使用 React + TypeScript,
|
||||
如果你在该项目中发现潜在的安全问题,或你认为可能发现了安全问题,请通过我们的[安全中心](https://security.bytedance.com/src) 或[漏洞报告邮箱](https://code.byted.org/flowdevops/cozeloop/blob/feat/release/sec@bytedance.com)通知字节跳动安全团队。
|
||||
请**不要**创建公开的 GitHub Issue。
|
||||
## 加入社区
|
||||
飞书移动端扫描以下二维码,加入 Coze Studio 技术交流群。
|
||||
|
||||
我们致力于构建一个开放、友好的开发者社区,欢迎所有对 AI Agent 开发感兴趣的开发者加入我们!
|
||||
|
||||
### 🐛 问题反馈与功能建议
|
||||
为了更高效地跟踪和解决问题,保证信息透明和便于协同,我们推荐通过以下方式参与:
|
||||
- **GitHub Issues**:[提交 Bug 报告或功能请求](https://github.com/coze-dev/coze-studio/issues)
|
||||
- **Pull Requests**:[贡献代码或文档改进](https://github.com/coze-dev/coze-studio/pulls)
|
||||
|
||||
### 💬 技术交流与讨论
|
||||
加入我们的技术交流群,与其他开发者分享经验、获取项目最新动态:
|
||||
|
||||
**飞书群聊**
|
||||
使用飞书移动端扫描下方二维码加入:
|
||||
|
||||

|
||||
|
||||
**Discord 服务器**
|
||||
点击加入:[Coze Community](https://discord.gg/sTVN9EVS4B)
|
||||
|
||||
**Telegram 群组**
|
||||
点击加入:Telegram Group [Coze](https://t.me/+pP9CkPnomDA0Mjgx)
|
||||
|
||||
## 致谢
|
||||
感谢所有为 Coze Studio 项目做出贡献的开发者和社区成员。特别感谢:
|
||||
|
||||
* Eino 框架团队提供的 LLM 集成支持
|
||||
* Cloudwego 团队开发的高性能框架
|
||||
* [Eino](https://github.com/cloudwego/eino) 框架团队 - 为 Coze Studio 的智能体和工作流运行时、模型抽象封装、知识库索引构建和检索提供了强大的支持
|
||||
* [FlowGram](https://github.com/bytedance/flowgram.ai) 团队 - 为 Coze Studio 的工作流画布编辑页提供了高质量的流程搭建引擎
|
||||
* [Hertz](https://github.com/cloudwego/hertz) 团队 - 高性能、强扩展性的 Go HTTP 框架,用于构建微服务
|
||||
* 所有参与测试和反馈的用户
|
||||
@ -31,7 +31,7 @@ WORKDIR /app
|
||||
# Install runtime dependencies for Go app and base for Python
|
||||
# pax-utils for scanelf, python3 for running Python, python3-dev for headers/shared libs
|
||||
# bind-tools for nslookup etc., file for debugging file types
|
||||
RUN apk add --no-cache pax-utils python3 python3-dev bind-tools file deno
|
||||
RUN apk add --no-cache pax-utils python3 python3-dev bind-tools file deno curl
|
||||
|
||||
# Install Python build dependencies, create venv, install packages, then remove build deps
|
||||
RUN apk add --no-cache --virtual .python-build-deps build-base py3-pip git && \
|
||||
@ -81,6 +81,9 @@ EXPOSE 8888
|
||||
|
||||
# Use a script to start both applications
|
||||
COPY backend/script/bootstrap.sh /app/bootstrap.sh
|
||||
RUN chmod +x /app/bootstrap.sh
|
||||
COPY docker/volumes/elasticsearch/setup_es.sh /app/setup_es.sh
|
||||
COPY docker/volumes/elasticsearch/es_index_schema /app/es_index_schemas
|
||||
|
||||
RUN chmod +x /app/bootstrap.sh /app/setup_es.sh
|
||||
|
||||
CMD ["/app/bootstrap.sh"]
|
||||
|
||||
@ -555,7 +555,11 @@ func CreateProjectConversationDef(ctx context.Context, c *app.RequestContext) {
|
||||
return
|
||||
}
|
||||
|
||||
resp := new(workflow.CreateProjectConversationDefResponse)
|
||||
resp, err := appworkflow.SVC.CreateApplicationConversationDef(ctx, &req)
|
||||
if err != nil {
|
||||
internalServerErrorResponse(ctx, c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(consts.StatusOK, resp)
|
||||
}
|
||||
@ -570,8 +574,11 @@ func UpdateProjectConversationDef(ctx context.Context, c *app.RequestContext) {
|
||||
invalidParamRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
resp := new(workflow.UpdateProjectConversationDefResponse)
|
||||
resp, err := appworkflow.SVC.UpdateApplicationConversationDef(ctx, &req)
|
||||
if err != nil {
|
||||
internalServerErrorResponse(ctx, c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(consts.StatusOK, resp)
|
||||
}
|
||||
@ -587,7 +594,11 @@ func DeleteProjectConversationDef(ctx context.Context, c *app.RequestContext) {
|
||||
return
|
||||
}
|
||||
|
||||
resp := new(workflow.DeleteProjectConversationDefResponse)
|
||||
resp, err := appworkflow.SVC.DeleteApplicationConversationDef(ctx, &req)
|
||||
if err != nil {
|
||||
internalServerErrorResponse(ctx, c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(consts.StatusOK, resp)
|
||||
}
|
||||
@ -603,7 +614,11 @@ func ListProjectConversationDef(ctx context.Context, c *app.RequestContext) {
|
||||
return
|
||||
}
|
||||
|
||||
resp := new(workflow.ListProjectConversationResponse)
|
||||
resp, err := appworkflow.SVC.ListApplicationConversationDef(ctx, &req)
|
||||
if err != nil {
|
||||
internalServerErrorResponse(ctx, c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(consts.StatusOK, resp)
|
||||
}
|
||||
@ -723,7 +738,11 @@ func GetChatFlowRole(ctx context.Context, c *app.RequestContext) {
|
||||
return
|
||||
}
|
||||
|
||||
resp := new(workflow.GetChatFlowRoleResponse)
|
||||
resp, err := appworkflow.SVC.GetChatFlowRole(ctx, &req)
|
||||
if err != nil {
|
||||
internalServerErrorResponse(ctx, c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(consts.StatusOK, resp)
|
||||
}
|
||||
@ -738,8 +757,11 @@ func CreateChatFlowRole(ctx context.Context, c *app.RequestContext) {
|
||||
invalidParamRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
resp := new(workflow.CreateChatFlowRoleResponse)
|
||||
resp, err := appworkflow.SVC.CreateChatFlowRole(ctx, &req)
|
||||
if err != nil {
|
||||
internalServerErrorResponse(ctx, c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(consts.StatusOK, resp)
|
||||
}
|
||||
@ -755,7 +777,11 @@ func DeleteChatFlowRole(ctx context.Context, c *app.RequestContext) {
|
||||
return
|
||||
}
|
||||
|
||||
resp := new(workflow.DeleteChatFlowRoleResponse)
|
||||
resp, err := appworkflow.SVC.DeleteChatFlowRole(ctx, &req)
|
||||
if err != nil {
|
||||
internalServerErrorResponse(ctx, c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(consts.StatusOK, resp)
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ import (
|
||||
|
||||
"github.com/alicebob/miniredis/v2"
|
||||
"github.com/bytedance/mockey"
|
||||
"github.com/cloudwego/eino/callbacks"
|
||||
model2 "github.com/cloudwego/eino/components/model"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/cloudwego/hertz/pkg/app"
|
||||
@ -102,6 +103,11 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
callbacks.AppendGlobalHandlers(service.GetTokenCallbackHandler())
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
type wfTestRunner struct {
|
||||
t *testing.T
|
||||
h *server.Hertz
|
||||
|
||||
@ -26,6 +26,8 @@ const (
|
||||
Scene_GenerateAgentInfo Scene = 8
|
||||
//openapi
|
||||
Scene_SceneOpenApi Scene = 9
|
||||
// 工作流
|
||||
Scene_SceneWorkflow Scene = 50
|
||||
)
|
||||
|
||||
func (p Scene) String() string {
|
||||
|
||||
@ -263,6 +263,7 @@ func toAPIParameter(paramMeta paramMetaInfo, sc *openapi3.Schema) (*common.APIPa
|
||||
}
|
||||
|
||||
if sc.Default != nil {
|
||||
apiParam.GlobalDefault = ptr.Of(fmt.Sprintf("%v", sc.Default))
|
||||
apiParam.LocalDefault = ptr.Of(fmt.Sprintf("%v", sc.Default))
|
||||
}
|
||||
|
||||
|
||||
@ -473,7 +473,10 @@ const (
|
||||
NodeType_Input NodeType = 30
|
||||
NodeType_Batch NodeType = 28
|
||||
NodeType_Continue NodeType = 29
|
||||
NodeType_MessageList NodeType = 37
|
||||
NodeType_AssignVariable NodeType = 40
|
||||
NodeType_ConversationList NodeType = 53
|
||||
NodeType_CreateMessage NodeType = 55
|
||||
NodeType_JsonSerialization NodeType = 58
|
||||
NodeType_JsonDeserialization NodeType = 59
|
||||
NodeType_DatasetDelete NodeType = 60
|
||||
@ -533,8 +536,14 @@ func (p NodeType) String() string {
|
||||
return "Batch"
|
||||
case NodeType_Continue:
|
||||
return "Continue"
|
||||
case NodeType_MessageList:
|
||||
return "MessageList"
|
||||
case NodeType_AssignVariable:
|
||||
return "AssignVariable"
|
||||
case NodeType_ConversationList:
|
||||
return "ConversationList"
|
||||
case NodeType_CreateMessage:
|
||||
return "CreateMessage"
|
||||
case NodeType_JsonSerialization:
|
||||
return "JsonSerialization"
|
||||
case NodeType_JsonDeserialization:
|
||||
@ -599,8 +608,14 @@ func NodeTypeFromString(s string) (NodeType, error) {
|
||||
return NodeType_Batch, nil
|
||||
case "Continue":
|
||||
return NodeType_Continue, nil
|
||||
case "MessageList":
|
||||
return NodeType_MessageList, nil
|
||||
case "AssignVariable":
|
||||
return NodeType_AssignVariable, nil
|
||||
case "ConversationList":
|
||||
return NodeType_ConversationList, nil
|
||||
case "CreateMessage":
|
||||
return NodeType_CreateMessage, nil
|
||||
case "JsonSerialization":
|
||||
return NodeType_JsonSerialization, nil
|
||||
case "JsonDeserialization":
|
||||
@ -657,11 +672,14 @@ const (
|
||||
NodeTemplateType_Input NodeTemplateType = 30
|
||||
NodeTemplateType_Batch NodeTemplateType = 28
|
||||
NodeTemplateType_Continue NodeTemplateType = 29
|
||||
NodeTemplateType_MessageList NodeTemplateType = 37
|
||||
NodeTemplateType_AssignVariable NodeTemplateType = 40
|
||||
NodeTemplateType_DatabaseInsert NodeTemplateType = 41
|
||||
NodeTemplateType_DatabaseUpdate NodeTemplateType = 42
|
||||
NodeTemplateType_DatabasesELECT NodeTemplateType = 43
|
||||
NodeTemplateType_DatabaseDelete NodeTemplateType = 44
|
||||
NodeTemplateType_ConversationList NodeTemplateType = 53
|
||||
NodeTemplateType_CreateMessage NodeTemplateType = 55
|
||||
NodeTemplateType_JsonSerialization NodeTemplateType = 58
|
||||
NodeTemplateType_JsonDeserialization NodeTemplateType = 59
|
||||
NodeTemplateType_DatasetDelete NodeTemplateType = 60
|
||||
@ -723,6 +741,8 @@ func (p NodeTemplateType) String() string {
|
||||
return "Batch"
|
||||
case NodeTemplateType_Continue:
|
||||
return "Continue"
|
||||
case NodeTemplateType_MessageList:
|
||||
return "MessageList"
|
||||
case NodeTemplateType_AssignVariable:
|
||||
return "AssignVariable"
|
||||
case NodeTemplateType_DatabaseInsert:
|
||||
@ -733,6 +753,10 @@ func (p NodeTemplateType) String() string {
|
||||
return "DatabasesELECT"
|
||||
case NodeTemplateType_DatabaseDelete:
|
||||
return "DatabaseDelete"
|
||||
case NodeTemplateType_ConversationList:
|
||||
return "ConversationList"
|
||||
case NodeTemplateType_CreateMessage:
|
||||
return "CreateMessage"
|
||||
case NodeTemplateType_JsonSerialization:
|
||||
return "JsonSerialization"
|
||||
case NodeTemplateType_JsonDeserialization:
|
||||
@ -799,6 +823,8 @@ func NodeTemplateTypeFromString(s string) (NodeTemplateType, error) {
|
||||
return NodeTemplateType_Batch, nil
|
||||
case "Continue":
|
||||
return NodeTemplateType_Continue, nil
|
||||
case "MessageList":
|
||||
return NodeTemplateType_MessageList, nil
|
||||
case "AssignVariable":
|
||||
return NodeTemplateType_AssignVariable, nil
|
||||
case "DatabaseInsert":
|
||||
@ -809,6 +835,10 @@ func NodeTemplateTypeFromString(s string) (NodeTemplateType, error) {
|
||||
return NodeTemplateType_DatabasesELECT, nil
|
||||
case "DatabaseDelete":
|
||||
return NodeTemplateType_DatabaseDelete, nil
|
||||
case "ConversationList":
|
||||
return NodeTemplateType_ConversationList, nil
|
||||
case "CreateMessage":
|
||||
return NodeTemplateType_CreateMessage, nil
|
||||
case "JsonSerialization":
|
||||
return NodeTemplateType_JsonSerialization, nil
|
||||
case "JsonDeserialization":
|
||||
@ -64103,7 +64133,7 @@ func (p *ChatFlowRole) String() string {
|
||||
}
|
||||
|
||||
type CreateChatFlowRoleRequest struct {
|
||||
ChatFlowRole *ChatFlowRole `thrift:"ChatFlowRole,1" json:"chat_flow_role" form:"ChatFlowRole" query:"ChatFlowRole"`
|
||||
ChatFlowRole *ChatFlowRole `thrift:"ChatFlowRole,1" json:"chat_flow_role" query:"chat_flow_role" `
|
||||
Base *base.Base `thrift:"Base,255,optional" form:"Base" json:"Base,omitempty" query:"Base"`
|
||||
}
|
||||
|
||||
@ -64302,7 +64332,9 @@ func (p *CreateChatFlowRoleRequest) String() string {
|
||||
|
||||
type CreateChatFlowRoleResponse struct {
|
||||
// 数据库中ID
|
||||
ID string `thrift:"ID,1" form:"ID" json:"ID" query:"ID"`
|
||||
ID string `thrift:"ID,1" json:"id" query:"id" `
|
||||
Code int64 `thrift:"code,253,required" form:"code,required" json:"code,required" query:"code,required"`
|
||||
Msg string `thrift:"msg,254,required" form:"msg,required" json:"msg,required" query:"msg,required"`
|
||||
BaseResp *base.BaseResp `thrift:"BaseResp,255,required" form:"BaseResp,required" json:"BaseResp,required" query:"BaseResp,required"`
|
||||
}
|
||||
|
||||
@ -64317,6 +64349,14 @@ func (p *CreateChatFlowRoleResponse) GetID() (v string) {
|
||||
return p.ID
|
||||
}
|
||||
|
||||
func (p *CreateChatFlowRoleResponse) GetCode() (v int64) {
|
||||
return p.Code
|
||||
}
|
||||
|
||||
func (p *CreateChatFlowRoleResponse) GetMsg() (v string) {
|
||||
return p.Msg
|
||||
}
|
||||
|
||||
var CreateChatFlowRoleResponse_BaseResp_DEFAULT *base.BaseResp
|
||||
|
||||
func (p *CreateChatFlowRoleResponse) GetBaseResp() (v *base.BaseResp) {
|
||||
@ -64328,6 +64368,8 @@ func (p *CreateChatFlowRoleResponse) GetBaseResp() (v *base.BaseResp) {
|
||||
|
||||
var fieldIDToName_CreateChatFlowRoleResponse = map[int16]string{
|
||||
1: "ID",
|
||||
253: "code",
|
||||
254: "msg",
|
||||
255: "BaseResp",
|
||||
}
|
||||
|
||||
@ -64338,6 +64380,8 @@ func (p *CreateChatFlowRoleResponse) IsSetBaseResp() bool {
|
||||
func (p *CreateChatFlowRoleResponse) Read(iprot thrift.TProtocol) (err error) {
|
||||
var fieldTypeId thrift.TType
|
||||
var fieldId int16
|
||||
var issetCode bool = false
|
||||
var issetMsg bool = false
|
||||
var issetBaseResp bool = false
|
||||
|
||||
if _, err = iprot.ReadStructBegin(); err != nil {
|
||||
@ -64362,6 +64406,24 @@ func (p *CreateChatFlowRoleResponse) Read(iprot thrift.TProtocol) (err error) {
|
||||
} else if err = iprot.Skip(fieldTypeId); err != nil {
|
||||
goto SkipFieldError
|
||||
}
|
||||
case 253:
|
||||
if fieldTypeId == thrift.I64 {
|
||||
if err = p.ReadField253(iprot); err != nil {
|
||||
goto ReadFieldError
|
||||
}
|
||||
issetCode = true
|
||||
} else if err = iprot.Skip(fieldTypeId); err != nil {
|
||||
goto SkipFieldError
|
||||
}
|
||||
case 254:
|
||||
if fieldTypeId == thrift.STRING {
|
||||
if err = p.ReadField254(iprot); err != nil {
|
||||
goto ReadFieldError
|
||||
}
|
||||
issetMsg = true
|
||||
} else if err = iprot.Skip(fieldTypeId); err != nil {
|
||||
goto SkipFieldError
|
||||
}
|
||||
case 255:
|
||||
if fieldTypeId == thrift.STRUCT {
|
||||
if err = p.ReadField255(iprot); err != nil {
|
||||
@ -64384,6 +64446,16 @@ func (p *CreateChatFlowRoleResponse) Read(iprot thrift.TProtocol) (err error) {
|
||||
goto ReadStructEndError
|
||||
}
|
||||
|
||||
if !issetCode {
|
||||
fieldId = 253
|
||||
goto RequiredFieldNotSetError
|
||||
}
|
||||
|
||||
if !issetMsg {
|
||||
fieldId = 254
|
||||
goto RequiredFieldNotSetError
|
||||
}
|
||||
|
||||
if !issetBaseResp {
|
||||
fieldId = 255
|
||||
goto RequiredFieldNotSetError
|
||||
@ -64417,6 +64489,28 @@ func (p *CreateChatFlowRoleResponse) ReadField1(iprot thrift.TProtocol) error {
|
||||
p.ID = _field
|
||||
return nil
|
||||
}
|
||||
func (p *CreateChatFlowRoleResponse) ReadField253(iprot thrift.TProtocol) error {
|
||||
|
||||
var _field int64
|
||||
if v, err := iprot.ReadI64(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
_field = v
|
||||
}
|
||||
p.Code = _field
|
||||
return nil
|
||||
}
|
||||
func (p *CreateChatFlowRoleResponse) ReadField254(iprot thrift.TProtocol) error {
|
||||
|
||||
var _field string
|
||||
if v, err := iprot.ReadString(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
_field = v
|
||||
}
|
||||
p.Msg = _field
|
||||
return nil
|
||||
}
|
||||
func (p *CreateChatFlowRoleResponse) ReadField255(iprot thrift.TProtocol) error {
|
||||
_field := base.NewBaseResp()
|
||||
if err := _field.Read(iprot); err != nil {
|
||||
@ -64436,6 +64530,14 @@ func (p *CreateChatFlowRoleResponse) Write(oprot thrift.TProtocol) (err error) {
|
||||
fieldId = 1
|
||||
goto WriteFieldError
|
||||
}
|
||||
if err = p.writeField253(oprot); err != nil {
|
||||
fieldId = 253
|
||||
goto WriteFieldError
|
||||
}
|
||||
if err = p.writeField254(oprot); err != nil {
|
||||
fieldId = 254
|
||||
goto WriteFieldError
|
||||
}
|
||||
if err = p.writeField255(oprot); err != nil {
|
||||
fieldId = 255
|
||||
goto WriteFieldError
|
||||
@ -64474,6 +64576,38 @@ WriteFieldBeginError:
|
||||
WriteFieldEndError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err)
|
||||
}
|
||||
func (p *CreateChatFlowRoleResponse) writeField253(oprot thrift.TProtocol) (err error) {
|
||||
if err = oprot.WriteFieldBegin("code", thrift.I64, 253); err != nil {
|
||||
goto WriteFieldBeginError
|
||||
}
|
||||
if err := oprot.WriteI64(p.Code); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = oprot.WriteFieldEnd(); err != nil {
|
||||
goto WriteFieldEndError
|
||||
}
|
||||
return nil
|
||||
WriteFieldBeginError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 253 begin error: ", p), err)
|
||||
WriteFieldEndError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 253 end error: ", p), err)
|
||||
}
|
||||
func (p *CreateChatFlowRoleResponse) writeField254(oprot thrift.TProtocol) (err error) {
|
||||
if err = oprot.WriteFieldBegin("msg", thrift.STRING, 254); err != nil {
|
||||
goto WriteFieldBeginError
|
||||
}
|
||||
if err := oprot.WriteString(p.Msg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = oprot.WriteFieldEnd(); err != nil {
|
||||
goto WriteFieldEndError
|
||||
}
|
||||
return nil
|
||||
WriteFieldBeginError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 254 begin error: ", p), err)
|
||||
WriteFieldEndError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 254 end error: ", p), err)
|
||||
}
|
||||
func (p *CreateChatFlowRoleResponse) writeField255(oprot thrift.TProtocol) (err error) {
|
||||
if err = oprot.WriteFieldBegin("BaseResp", thrift.STRUCT, 255); err != nil {
|
||||
goto WriteFieldBeginError
|
||||
@ -64500,10 +64634,10 @@ func (p *CreateChatFlowRoleResponse) String() string {
|
||||
}
|
||||
|
||||
type DeleteChatFlowRoleRequest struct {
|
||||
WorkflowID string `thrift:"WorkflowID,1" form:"WorkflowID" json:"WorkflowID" query:"WorkflowID"`
|
||||
ConnectorID string `thrift:"ConnectorID,2" form:"ConnectorID" json:"ConnectorID" query:"ConnectorID"`
|
||||
WorkflowID string `thrift:"WorkflowID,1" json:"workflow_id" query:"workflow_id" `
|
||||
ConnectorID string `thrift:"ConnectorID,2" json:"connector_id" query:"connector_id" `
|
||||
// 数据库中ID
|
||||
ID string `thrift:"ID,4" form:"ID" json:"ID" query:"ID"`
|
||||
ID string `thrift:"ID,4" json:"id" query:"id" `
|
||||
Base *base.Base `thrift:"Base,255,optional" form:"Base" json:"Base,omitempty" query:"Base"`
|
||||
}
|
||||
|
||||
@ -64936,12 +65070,12 @@ func (p *DeleteChatFlowRoleResponse) String() string {
|
||||
}
|
||||
|
||||
type GetChatFlowRoleRequest struct {
|
||||
WorkflowID string `thrift:"WorkflowID,1" form:"WorkflowID" json:"WorkflowID" query:"WorkflowID"`
|
||||
ConnectorID string `thrift:"ConnectorID,2" form:"ConnectorID" json:"ConnectorID" query:"ConnectorID"`
|
||||
IsDebug bool `thrift:"IsDebug,3" form:"IsDebug" json:"IsDebug" query:"IsDebug"`
|
||||
WorkflowID string `thrift:"WorkflowID,1" json:"workflow_id" query:"workflow_id" `
|
||||
ConnectorID string `thrift:"ConnectorID,2" json:"connector_id" query:"connector_id" `
|
||||
IsDebug bool `thrift:"IsDebug,3" json:"is_debug" query:"is_debug" `
|
||||
// 4: optional string AppID (api.query = "app_id")
|
||||
Ext map[string]string `thrift:"Ext,5,optional" json:"Ext,omitempty" query:"ext"`
|
||||
Base *base.Base `thrift:"Base,255,optional" form:"Base" json:"Base,omitempty" query:"Base"`
|
||||
Base *base.Base `thrift:"Base,255,optional" json:"base" query:"base" `
|
||||
}
|
||||
|
||||
func NewGetChatFlowRoleRequest() *GetChatFlowRoleRequest {
|
||||
@ -65304,8 +65438,10 @@ func (p *GetChatFlowRoleRequest) String() string {
|
||||
}
|
||||
|
||||
type GetChatFlowRoleResponse struct {
|
||||
Role *ChatFlowRole `thrift:"Role,1,optional" form:"Role" json:"Role,omitempty" query:"Role"`
|
||||
BaseResp *base.BaseResp `thrift:"BaseResp,255,required" form:"BaseResp,required" json:"BaseResp,required" query:"BaseResp,required"`
|
||||
Code int64 `thrift:"code,1,required" form:"code,required" json:"code,required" query:"code,required"`
|
||||
Msg string `thrift:"msg,2,required" form:"msg,required" json:"msg,required" query:"msg,required"`
|
||||
Role *ChatFlowRole `thrift:"Role,3,optional" json:"role" query:"role" `
|
||||
BaseResp *base.BaseResp `thrift:"BaseResp,255,required" json:"base_resp" query:"base_resp,required" `
|
||||
}
|
||||
|
||||
func NewGetChatFlowRoleResponse() *GetChatFlowRoleResponse {
|
||||
@ -65315,6 +65451,14 @@ func NewGetChatFlowRoleResponse() *GetChatFlowRoleResponse {
|
||||
func (p *GetChatFlowRoleResponse) InitDefault() {
|
||||
}
|
||||
|
||||
func (p *GetChatFlowRoleResponse) GetCode() (v int64) {
|
||||
return p.Code
|
||||
}
|
||||
|
||||
func (p *GetChatFlowRoleResponse) GetMsg() (v string) {
|
||||
return p.Msg
|
||||
}
|
||||
|
||||
var GetChatFlowRoleResponse_Role_DEFAULT *ChatFlowRole
|
||||
|
||||
func (p *GetChatFlowRoleResponse) GetRole() (v *ChatFlowRole) {
|
||||
@ -65334,7 +65478,9 @@ func (p *GetChatFlowRoleResponse) GetBaseResp() (v *base.BaseResp) {
|
||||
}
|
||||
|
||||
var fieldIDToName_GetChatFlowRoleResponse = map[int16]string{
|
||||
1: "Role",
|
||||
1: "code",
|
||||
2: "msg",
|
||||
3: "Role",
|
||||
255: "BaseResp",
|
||||
}
|
||||
|
||||
@ -65349,6 +65495,8 @@ func (p *GetChatFlowRoleResponse) IsSetBaseResp() bool {
|
||||
func (p *GetChatFlowRoleResponse) Read(iprot thrift.TProtocol) (err error) {
|
||||
var fieldTypeId thrift.TType
|
||||
var fieldId int16
|
||||
var issetCode bool = false
|
||||
var issetMsg bool = false
|
||||
var issetBaseResp bool = false
|
||||
|
||||
if _, err = iprot.ReadStructBegin(); err != nil {
|
||||
@ -65366,10 +65514,28 @@ func (p *GetChatFlowRoleResponse) Read(iprot thrift.TProtocol) (err error) {
|
||||
|
||||
switch fieldId {
|
||||
case 1:
|
||||
if fieldTypeId == thrift.STRUCT {
|
||||
if fieldTypeId == thrift.I64 {
|
||||
if err = p.ReadField1(iprot); err != nil {
|
||||
goto ReadFieldError
|
||||
}
|
||||
issetCode = true
|
||||
} else if err = iprot.Skip(fieldTypeId); err != nil {
|
||||
goto SkipFieldError
|
||||
}
|
||||
case 2:
|
||||
if fieldTypeId == thrift.STRING {
|
||||
if err = p.ReadField2(iprot); err != nil {
|
||||
goto ReadFieldError
|
||||
}
|
||||
issetMsg = true
|
||||
} else if err = iprot.Skip(fieldTypeId); err != nil {
|
||||
goto SkipFieldError
|
||||
}
|
||||
case 3:
|
||||
if fieldTypeId == thrift.STRUCT {
|
||||
if err = p.ReadField3(iprot); err != nil {
|
||||
goto ReadFieldError
|
||||
}
|
||||
} else if err = iprot.Skip(fieldTypeId); err != nil {
|
||||
goto SkipFieldError
|
||||
}
|
||||
@ -65395,6 +65561,16 @@ func (p *GetChatFlowRoleResponse) Read(iprot thrift.TProtocol) (err error) {
|
||||
goto ReadStructEndError
|
||||
}
|
||||
|
||||
if !issetCode {
|
||||
fieldId = 1
|
||||
goto RequiredFieldNotSetError
|
||||
}
|
||||
|
||||
if !issetMsg {
|
||||
fieldId = 2
|
||||
goto RequiredFieldNotSetError
|
||||
}
|
||||
|
||||
if !issetBaseResp {
|
||||
fieldId = 255
|
||||
goto RequiredFieldNotSetError
|
||||
@ -65418,6 +65594,28 @@ RequiredFieldNotSetError:
|
||||
}
|
||||
|
||||
func (p *GetChatFlowRoleResponse) ReadField1(iprot thrift.TProtocol) error {
|
||||
|
||||
var _field int64
|
||||
if v, err := iprot.ReadI64(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
_field = v
|
||||
}
|
||||
p.Code = _field
|
||||
return nil
|
||||
}
|
||||
func (p *GetChatFlowRoleResponse) ReadField2(iprot thrift.TProtocol) error {
|
||||
|
||||
var _field string
|
||||
if v, err := iprot.ReadString(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
_field = v
|
||||
}
|
||||
p.Msg = _field
|
||||
return nil
|
||||
}
|
||||
func (p *GetChatFlowRoleResponse) ReadField3(iprot thrift.TProtocol) error {
|
||||
_field := NewChatFlowRole()
|
||||
if err := _field.Read(iprot); err != nil {
|
||||
return err
|
||||
@ -65444,6 +65642,14 @@ func (p *GetChatFlowRoleResponse) Write(oprot thrift.TProtocol) (err error) {
|
||||
fieldId = 1
|
||||
goto WriteFieldError
|
||||
}
|
||||
if err = p.writeField2(oprot); err != nil {
|
||||
fieldId = 2
|
||||
goto WriteFieldError
|
||||
}
|
||||
if err = p.writeField3(oprot); err != nil {
|
||||
fieldId = 3
|
||||
goto WriteFieldError
|
||||
}
|
||||
if err = p.writeField255(oprot); err != nil {
|
||||
fieldId = 255
|
||||
goto WriteFieldError
|
||||
@ -65467,8 +65673,40 @@ WriteStructEndError:
|
||||
}
|
||||
|
||||
func (p *GetChatFlowRoleResponse) writeField1(oprot thrift.TProtocol) (err error) {
|
||||
if err = oprot.WriteFieldBegin("code", thrift.I64, 1); err != nil {
|
||||
goto WriteFieldBeginError
|
||||
}
|
||||
if err := oprot.WriteI64(p.Code); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = oprot.WriteFieldEnd(); err != nil {
|
||||
goto WriteFieldEndError
|
||||
}
|
||||
return nil
|
||||
WriteFieldBeginError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err)
|
||||
WriteFieldEndError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err)
|
||||
}
|
||||
func (p *GetChatFlowRoleResponse) writeField2(oprot thrift.TProtocol) (err error) {
|
||||
if err = oprot.WriteFieldBegin("msg", thrift.STRING, 2); err != nil {
|
||||
goto WriteFieldBeginError
|
||||
}
|
||||
if err := oprot.WriteString(p.Msg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = oprot.WriteFieldEnd(); err != nil {
|
||||
goto WriteFieldEndError
|
||||
}
|
||||
return nil
|
||||
WriteFieldBeginError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 2 begin error: ", p), err)
|
||||
WriteFieldEndError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 2 end error: ", p), err)
|
||||
}
|
||||
func (p *GetChatFlowRoleResponse) writeField3(oprot thrift.TProtocol) (err error) {
|
||||
if p.IsSetRole() {
|
||||
if err = oprot.WriteFieldBegin("Role", thrift.STRUCT, 1); err != nil {
|
||||
if err = oprot.WriteFieldBegin("Role", thrift.STRUCT, 3); err != nil {
|
||||
goto WriteFieldBeginError
|
||||
}
|
||||
if err := p.Role.Write(oprot); err != nil {
|
||||
@ -65480,9 +65718,9 @@ func (p *GetChatFlowRoleResponse) writeField1(oprot thrift.TProtocol) (err error
|
||||
}
|
||||
return nil
|
||||
WriteFieldBeginError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err)
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 3 begin error: ", p), err)
|
||||
WriteFieldEndError:
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err)
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field 3 end error: ", p), err)
|
||||
}
|
||||
func (p *GetChatFlowRoleResponse) writeField255(oprot thrift.TProtocol) (err error) {
|
||||
if err = oprot.WriteFieldBegin("BaseResp", thrift.STRUCT, 255); err != nil {
|
||||
|
||||
@ -60,6 +60,7 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/conv"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/safego"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/taskgroup"
|
||||
"github.com/coze-dev/coze-studio/backend/types/consts"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
@ -183,18 +184,19 @@ func (a *APPApplicationService) DraftProjectDelete(ctx context.Context, req *pro
|
||||
logs.CtxErrorf(ctx, "publish project '%d' failed, err=%v", req.ProjectID, err)
|
||||
}
|
||||
|
||||
err = a.deleteAPPResources(ctx, req.ProjectID)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "delete app '%d' resources failed, err=%v", req.ProjectID, err)
|
||||
}
|
||||
safego.Go(ctx, func() {
|
||||
// When an app is deleted, resource deletion is currently handled as a weak dependency, meaning some resources might not be deleted, but they will be inaccessible to the user.
|
||||
// TODO:: Application resources need to check the deletion status of the application
|
||||
a.deleteAPPResources(ctx, req.ProjectID)
|
||||
})
|
||||
|
||||
resp = &projectAPI.DraftProjectDeleteResponse{}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (a *APPApplicationService) deleteAPPResources(ctx context.Context, appID int64) (err error) {
|
||||
err = plugin.PluginApplicationSVC.DeleteAPPAllPlugins(ctx, appID)
|
||||
func (a *APPApplicationService) deleteAPPResources(ctx context.Context, appID int64) {
|
||||
err := plugin.PluginApplicationSVC.DeleteAPPAllPlugins(ctx, appID)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "delete app '%d' plugins failed, err=%v", appID, err)
|
||||
}
|
||||
@ -218,8 +220,6 @@ func (a *APPApplicationService) deleteAPPResources(ctx context.Context, appID in
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "delete app '%d' workflow failed, err=%v", appID, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *APPApplicationService) DraftProjectUpdate(ctx context.Context, req *projectAPI.DraftProjectUpdateRequest) (resp *projectAPI.DraftProjectUpdateResponse, err error) {
|
||||
|
||||
@ -20,9 +20,8 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
|
||||
@ -33,14 +32,6 @@ import (
|
||||
func APIParamsToOpenapiOperation(reqParams, respParams []*common.APIParameter) (*openapi3.Operation, error) {
|
||||
op := &openapi3.Operation{}
|
||||
|
||||
if reqParams != nil && len(reqParams) == 0 {
|
||||
op.Parameters = []*openapi3.ParameterRef{}
|
||||
op.RequestBody = entity.DefaultOpenapi3RequestBody()
|
||||
}
|
||||
if respParams != nil && len(respParams) == 0 {
|
||||
op.Responses = entity.DefaultOpenapi3Responses()
|
||||
}
|
||||
|
||||
hasSetReqBody := false
|
||||
hasSetParams := false
|
||||
|
||||
@ -136,6 +127,16 @@ func APIParamsToOpenapiOperation(reqParams, respParams []*common.APIParameter) (
|
||||
}
|
||||
}
|
||||
|
||||
if op.Parameters == nil {
|
||||
op.Parameters = []*openapi3.ParameterRef{}
|
||||
}
|
||||
if op.RequestBody == nil {
|
||||
op.RequestBody = entity.DefaultOpenapi3RequestBody()
|
||||
}
|
||||
if op.Responses == nil {
|
||||
op.Responses = entity.DefaultOpenapi3Responses()
|
||||
}
|
||||
|
||||
return op, nil
|
||||
}
|
||||
|
||||
|
||||
@ -140,7 +140,7 @@ func (c *ConversationApplicationService) CreateConversation(ctx context.Context,
|
||||
Id: conversationData.ID,
|
||||
LastSectionID: &conversationData.SectionID,
|
||||
ConnectorID: &conversationData.ConnectorID,
|
||||
CreatedAt: conversationData.CreatedAt,
|
||||
CreatedAt: conversationData.CreatedAt / 1000,
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
@ -176,7 +176,7 @@ func (c *ConversationApplicationService) ListConversation(ctx context.Context, r
|
||||
Id: conv.ID,
|
||||
LastSectionID: &conv.SectionID,
|
||||
ConnectorID: &conv.ConnectorID,
|
||||
CreatedAt: conv.CreatedAt,
|
||||
CreatedAt: conv.CreatedAt / 1000,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -299,6 +299,7 @@ func buildARSM2ApiMessage(chunk *entity.AgentRunResponse) []byte {
|
||||
MetaData: chunkMessageItem.Ext,
|
||||
ChatID: strconv.FormatInt(chunkMessageItem.RunID, 10),
|
||||
ReasoningContent: chunkMessageItem.ReasoningContent,
|
||||
CreatedAt: ptr.Of(chunkMessageItem.CreatedAt / 1000),
|
||||
}
|
||||
|
||||
mCM, _ := json.Marshal(chunkMessage)
|
||||
|
||||
@ -110,8 +110,8 @@ func (m *OpenapiMessageApplication) buildMessageListResponse(ctx context.Context
|
||||
Content: content,
|
||||
ContentType: string(dm.ContentType),
|
||||
SectionID: strconv.FormatInt(dm.SectionID, 10),
|
||||
CreatedAt: dm.CreatedAt,
|
||||
UpdatedAt: dm.UpdatedAt,
|
||||
CreatedAt: dm.CreatedAt / 1000,
|
||||
UpdatedAt: dm.UpdatedAt / 1000,
|
||||
ChatID: dm.RunID,
|
||||
MetaData: dm.Ext,
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cloudwego/eino-ext/components/embedding/ark"
|
||||
ollamaEmb "github.com/cloudwego/eino-ext/components/embedding/ollama"
|
||||
"github.com/cloudwego/eino-ext/components/embedding/openai"
|
||||
ao "github.com/cloudwego/eino-ext/components/model/ark"
|
||||
"github.com/cloudwego/eino-ext/components/model/deepseek"
|
||||
@ -35,6 +36,7 @@ import (
|
||||
"github.com/cloudwego/eino-ext/components/model/qwen"
|
||||
"github.com/cloudwego/eino/components/prompt"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/impl/embedding/http"
|
||||
"github.com/milvus-io/milvus/client/v2/milvusclient"
|
||||
"github.com/volcengine/volc-sdk-golang/service/vikingdb"
|
||||
"github.com/volcengine/volc-sdk-golang/service/visual"
|
||||
@ -111,6 +113,9 @@ func InitService(c *ServiceComponents) (*KnowledgeApplicationService, error) {
|
||||
case "ve":
|
||||
ocrAK := os.Getenv("VE_OCR_AK")
|
||||
ocrSK := os.Getenv("VE_OCR_SK")
|
||||
if ocrAK == "" || ocrSK == "" {
|
||||
logs.Warnf("[ve_ocr] ak / sk not configured, ocr might not work well")
|
||||
}
|
||||
inst := visual.NewInstance()
|
||||
inst.Client.SetAccessKey(ocrAK)
|
||||
inst.Client.SetSecretKey(ocrSK)
|
||||
@ -346,6 +351,42 @@ func getEmbedding(ctx context.Context) (embedding.Embedder, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init ark embedding client failed, err=%w", err)
|
||||
}
|
||||
|
||||
case "ollama":
|
||||
var (
|
||||
ollamaEmbeddingBaseURL = os.Getenv("OLLAMA_EMBEDDING_BASE_URL")
|
||||
ollamaEmbeddingModel = os.Getenv("OLLAMA_EMBEDDING_MODEL")
|
||||
ollamaEmbeddingDims = os.Getenv("OLLAMA_EMBEDDING_DIMS")
|
||||
)
|
||||
|
||||
dims, err := strconv.ParseInt(ollamaEmbeddingDims, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init ollama embedding dims failed, err=%w", err)
|
||||
}
|
||||
|
||||
emb, err = wrap.NewOllamaEmbedder(ctx, &ollamaEmb.EmbeddingConfig{
|
||||
BaseURL: ollamaEmbeddingBaseURL,
|
||||
Model: ollamaEmbeddingModel,
|
||||
}, dims)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init ollama embedding failed, err=%w", err)
|
||||
}
|
||||
|
||||
|
||||
case "http":
|
||||
var (
|
||||
httpEmbeddingBaseURL = os.Getenv("HTTP_EMBEDDING_ADDR")
|
||||
httpEmbeddingDims = os.Getenv("HTTP_EMBEDDING_DIMS")
|
||||
)
|
||||
dims, err := strconv.ParseInt(httpEmbeddingDims, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init http embedding dims failed, err=%w", err)
|
||||
}
|
||||
emb, err = http.NewEmbedding(httpEmbeddingBaseURL, dims)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init http embedding failed, err=%w", err)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("init knowledge embedding failed, type not configured")
|
||||
}
|
||||
|
||||
@ -438,7 +438,7 @@ func (k *KnowledgeApplicationService) GetDocumentProgress(ctx context.Context, r
|
||||
DocumentID: domainResp.ProgressList[i].ID,
|
||||
Progress: int32(domainResp.ProgressList[i].Progress),
|
||||
Status: convertDocumentStatus2Model(domainResp.ProgressList[i].Status),
|
||||
StatusDescript: ptr.Of(convertDocumentStatus2Model(domainResp.ProgressList[i].Status).String()),
|
||||
StatusDescript: &domainResp.ProgressList[i].StatusMsg,
|
||||
DocumentName: domainResp.ProgressList[i].Name,
|
||||
RemainingTime: &domainResp.ProgressList[i].RemainingSec,
|
||||
Size: &domainResp.ProgressList[i].Size,
|
||||
|
||||
@ -18,9 +18,12 @@ package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/conf"
|
||||
pluginConf "github.com/coze-dev/coze-studio/backend/domain/plugin/conf"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/repository"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/service"
|
||||
@ -28,6 +31,9 @@ import (
|
||||
user "github.com/coze-dev/coze-studio/backend/domain/user/service"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type ServiceComponents struct {
|
||||
@ -68,6 +74,11 @@ func InitService(ctx context.Context, components *ServiceComponents) (*PluginApp
|
||||
OAuthRepo: oauthRepo,
|
||||
})
|
||||
|
||||
err = checkIDExist(ctx, pluginSVC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
PluginApplicationSVC.DomainSVC = pluginSVC
|
||||
PluginApplicationSVC.eventbus = components.EventBus
|
||||
PluginApplicationSVC.oss = components.OSS
|
||||
@ -77,3 +88,51 @@ func InitService(ctx context.Context, components *ServiceComponents) (*PluginApp
|
||||
|
||||
return PluginApplicationSVC, nil
|
||||
}
|
||||
|
||||
func checkIDExist(ctx context.Context, pluginService service.PluginService) error {
|
||||
pluginProducts := conf.GetAllPluginProducts()
|
||||
|
||||
pluginIDs := make([]int64, 0, len(pluginProducts))
|
||||
var toolIDs []int64
|
||||
for _, p := range pluginProducts {
|
||||
pluginIDs = append(pluginIDs, p.Info.ID)
|
||||
toolIDs = append(toolIDs, p.ToolIDs...)
|
||||
}
|
||||
|
||||
pluginInfos, err := pluginService.MGetDraftPlugins(ctx, pluginIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(pluginInfos) > 0 {
|
||||
conflictsIDs := make([]int64, 0, len(pluginInfos))
|
||||
for _, p := range pluginInfos {
|
||||
conflictsIDs = append(conflictsIDs, p.ID)
|
||||
}
|
||||
|
||||
return errorx.New(errno.ErrPluginIDExist,
|
||||
errorx.KV("plugin_id", strings.Join(slices.Transform(conflictsIDs, func(id int64) string {
|
||||
return strconv.FormatInt(id, 10)
|
||||
}), ",")),
|
||||
)
|
||||
}
|
||||
|
||||
tools, err := pluginService.MGetDraftTools(ctx, toolIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(tools) > 0 {
|
||||
conflictsIDs := make([]int64, 0, len(tools))
|
||||
for _, t := range tools {
|
||||
conflictsIDs = append(conflictsIDs, t.ID)
|
||||
}
|
||||
|
||||
return errorx.New(errno.ErrToolIDExist,
|
||||
errorx.KV("tool_id", strings.Join(slices.Transform(conflictsIDs, func(id int64) string {
|
||||
return strconv.FormatInt(id, 10)
|
||||
}), ",")),
|
||||
)
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
@ -250,7 +250,7 @@ func (p *PluginApplicationService) RegisterPluginMeta(ctx context.Context, req *
|
||||
if req.GetLocation() == common.AuthorizationServiceLocation_Query {
|
||||
loc = model.ParamInQuery
|
||||
} else if req.GetLocation() == common.AuthorizationServiceLocation_Header {
|
||||
loc = model.ParamInPath
|
||||
loc = model.ParamInHeader
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid location '%s'", req.GetLocation())
|
||||
}
|
||||
|
||||
@ -76,28 +76,38 @@ func (s *SearchApplicationService) GetDraftIntelligenceList(ctx context.Context,
|
||||
intelligenceDataList := make([]*intelligence.IntelligenceData, len(searchResp.Data))
|
||||
|
||||
logs.CtxDebugf(ctx, "[GetDraftIntelligenceList] searchResp.Data: %v", conv.DebugJsonToStr(searchResp.Data))
|
||||
if len(searchResp.Data) > 1 {
|
||||
for idx := range searchResp.Data[1:] {
|
||||
index := idx + 1
|
||||
data := searchResp.Data[index]
|
||||
tasks.Go(func() error {
|
||||
info, err := s.packIntelligenceData(ctx, data)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "[packIntelligenceData] failed id %v, type %d , name %s, err: %v", data.ID, data.Type, data.GetName(), err)
|
||||
return err
|
||||
}
|
||||
|
||||
for idx := range searchResp.Data {
|
||||
data := searchResp.Data[idx]
|
||||
index := idx
|
||||
tasks.Go(func() error {
|
||||
info, err := s.packIntelligenceData(ctx, data)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "[packIntelligenceData] failed id %v, type %d , name %s, err: %v", data.ID, data.Type, data.GetName(), err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
intelligenceDataList[index] = info
|
||||
return nil
|
||||
})
|
||||
|
||||
s.packIntelligenceData(ctx, data)
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
intelligenceDataList[index] = info
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(searchResp.Data) != 0 {
|
||||
info, err := s.packIntelligenceData(ctx, searchResp.Data[0])
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "[packIntelligenceData] failed id %v, type %d , name %s, err: %v", searchResp.Data[0].ID, searchResp.Data[0].Type, searchResp.Data[0].GetName(), err)
|
||||
return nil, err
|
||||
}
|
||||
lock.Lock()
|
||||
intelligenceDataList[0] = info
|
||||
lock.Unlock()
|
||||
}
|
||||
err = tasks.Wait()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_ = tasks.Wait()
|
||||
filterDataList := make([]*intelligence.IntelligenceData, 0)
|
||||
for _, data := range intelligenceDataList {
|
||||
if data != nil {
|
||||
|
||||
@ -86,25 +86,39 @@ func (s *SearchApplicationService) LibraryResourceList(ctx context.Context, req
|
||||
lock := sync.Mutex{}
|
||||
tasks := taskgroup.NewUninterruptibleTaskGroup(ctx, 10)
|
||||
resources := make([]*common.ResourceInfo, len(searchResp.Data))
|
||||
for idx := range searchResp.Data {
|
||||
v := searchResp.Data[idx]
|
||||
index := idx
|
||||
tasks.Go(func() error {
|
||||
ri, err := s.packResource(ctx, v)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "[LibraryResourceList] packResource failed, will ignore resID: %d, Name : %s, resType: %d, err: %v",
|
||||
v.ResID, v.GetName(), v.ResType, err)
|
||||
return err
|
||||
}
|
||||
if len(searchResp.Data) > 1 {
|
||||
for idx := range searchResp.Data[1:] {
|
||||
index := idx + 1
|
||||
v := searchResp.Data[index]
|
||||
tasks.Go(func() error {
|
||||
ri, err := s.packResource(ctx, v)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "[LibraryResourceList] packResource failed, will ignore resID: %d, Name : %s, resType: %d, err: %v",
|
||||
v.ResID, v.GetName(), v.ResType, err)
|
||||
return err
|
||||
}
|
||||
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
resources[index] = ri
|
||||
return nil
|
||||
})
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
resources[index] = ri
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(searchResp.Data) != 0 {
|
||||
ri, err := s.packResource(ctx, searchResp.Data[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lock.Lock()
|
||||
resources[0] = ri
|
||||
lock.Unlock()
|
||||
}
|
||||
err = tasks.Wait()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_ = tasks.Wait()
|
||||
filterResource := make([]*common.ResourceInfo, 0)
|
||||
for _, res := range resources {
|
||||
if res == nil {
|
||||
|
||||
@ -19,7 +19,10 @@ package user
|
||||
import (
|
||||
"context"
|
||||
"net/mail"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/developer_api"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/playground"
|
||||
@ -30,7 +33,8 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
langSlices "github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/types/consts"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
@ -56,6 +60,11 @@ func (u *UserApplicationService) PassportWebEmailRegisterV2(ctx context.Context,
|
||||
return nil, "", errorx.New(errno.ErrUserInvalidParamCode, errorx.KV("msg", "Invalid email"))
|
||||
}
|
||||
|
||||
// Allow Register Checker
|
||||
if !u.allowRegisterChecker(req.GetEmail()) {
|
||||
return nil, "", errorx.New(errno.ErrNotAllowedRegisterCode)
|
||||
}
|
||||
|
||||
userInfo, err := u.DomainSVC.Create(ctx, &user.CreateUserRequest{
|
||||
Email: req.GetEmail(),
|
||||
Password: req.GetPassword(),
|
||||
@ -77,6 +86,20 @@ func (u *UserApplicationService) PassportWebEmailRegisterV2(ctx context.Context,
|
||||
}, userInfo.SessionKey, nil
|
||||
}
|
||||
|
||||
func (u *UserApplicationService) allowRegisterChecker(email string) bool {
|
||||
disableUserRegistration := os.Getenv(consts.DisableUserRegistration)
|
||||
if strings.ToLower(disableUserRegistration) != "true" {
|
||||
return true
|
||||
}
|
||||
|
||||
allowedEmails := os.Getenv(consts.AllowRegistrationEmail)
|
||||
if allowedEmails == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return slices.Contains(strings.Split(allowedEmails, ","), strings.ToLower(email))
|
||||
}
|
||||
|
||||
// PassportWebLogoutGet 处理用户登出请求
|
||||
func (u *UserApplicationService) PassportWebLogoutGet(ctx context.Context, req *passport.PassportWebLogoutGetRequest) (
|
||||
resp *passport.PassportWebLogoutGetResponse, err error,
|
||||
@ -204,7 +227,7 @@ func (u *UserApplicationService) GetSpaceListV2(ctx context.Context, req *playgr
|
||||
return nil, err
|
||||
}
|
||||
|
||||
botSpaces := slices.Transform(spaces, func(space *entity.Space) *playground.BotSpaceV2 {
|
||||
botSpaces := langSlices.Transform(spaces, func(space *entity.Space) *playground.BotSpaceV2 {
|
||||
return &playground.BotSpaceV2{
|
||||
ID: space.ID,
|
||||
Name: space.Name,
|
||||
@ -230,7 +253,7 @@ func (u *UserApplicationService) GetSpaceListV2(ctx context.Context, req *playgr
|
||||
func (u *UserApplicationService) MGetUserBasicInfo(ctx context.Context, req *playground.MGetUserBasicInfoRequest) (
|
||||
resp *playground.MGetUserBasicInfoResponse, err error,
|
||||
) {
|
||||
userIDs, err := slices.TransformWithErrorCheck(req.GetUserIds(), func(s string) (int64, error) {
|
||||
userIDs, err := langSlices.TransformWithErrorCheck(req.GetUserIds(), func(s string) (int64, error) {
|
||||
return strconv.ParseInt(s, 10, 64)
|
||||
})
|
||||
if err != nil {
|
||||
@ -243,7 +266,7 @@ func (u *UserApplicationService) MGetUserBasicInfo(ctx context.Context, req *pla
|
||||
}
|
||||
|
||||
return &playground.MGetUserBasicInfoResponse{
|
||||
UserBasicInfoMap: slices.ToMap(userInfos, func(userInfo *entity.User) (string, *playground.UserBasicInfo) {
|
||||
UserBasicInfoMap: langSlices.ToMap(userInfos, func(userInfo *entity.User) (string, *playground.UserBasicInfo) {
|
||||
return strconv.FormatInt(userInfo.UserID, 10), userDo2PlaygroundTo(userInfo)
|
||||
}),
|
||||
Code: 0,
|
||||
|
||||
264
backend/application/workflow/chatflow.go
Normal file
264
backend/application/workflow/chatflow.go
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package workflow
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/coze-dev/coze-studio/backend/types/consts"
|
||||
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/application/base/ctxutil"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/maps"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/safego"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
func (w *ApplicationService) CreateApplicationConversationDef(ctx context.Context, req *workflow.CreateProjectConversationDefRequest) (resp *workflow.CreateProjectConversationDefResponse, err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = safego.NewPanicErr(panicErr, debug.Stack())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrConversationOfAppOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
|
||||
}
|
||||
}()
|
||||
|
||||
var (
|
||||
spaceID = mustParseInt64(req.GetSpaceID())
|
||||
appID = mustParseInt64(req.GetProjectID())
|
||||
userID = ctxutil.MustGetUIDFromCtx(ctx)
|
||||
)
|
||||
|
||||
if err := checkUserSpace(ctx, userID, spaceID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uniqueID, err := GetWorkflowDomainSVC().CreateDraftConversationTemplate(ctx, &vo.CreateConversationTemplateMeta{
|
||||
AppID: appID,
|
||||
SpaceID: spaceID,
|
||||
Name: req.GetConversationName(),
|
||||
UserID: userID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &workflow.CreateProjectConversationDefResponse{
|
||||
UniqueID: strconv.FormatInt(uniqueID, 10),
|
||||
SpaceID: req.GetSpaceID(),
|
||||
}, err
|
||||
}
|
||||
|
||||
func (w *ApplicationService) UpdateApplicationConversationDef(ctx context.Context, req *workflow.UpdateProjectConversationDefRequest) (resp *workflow.UpdateProjectConversationDefResponse, err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = safego.NewPanicErr(panicErr, debug.Stack())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrConversationOfAppOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
|
||||
}
|
||||
}()
|
||||
var (
|
||||
spaceID = mustParseInt64(req.GetSpaceID())
|
||||
templateID = mustParseInt64(req.GetUniqueID())
|
||||
appID = mustParseInt64(req.GetProjectID())
|
||||
userID = ctxutil.MustGetUIDFromCtx(ctx)
|
||||
)
|
||||
|
||||
if err := checkUserSpace(ctx, userID, spaceID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = GetWorkflowDomainSVC().UpdateDraftConversationTemplateName(ctx, appID, userID, templateID, req.GetConversationName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &workflow.UpdateProjectConversationDefResponse{}, err
|
||||
}
|
||||
|
||||
func (w *ApplicationService) DeleteApplicationConversationDef(ctx context.Context, req *workflow.DeleteProjectConversationDefRequest) (resp *workflow.DeleteProjectConversationDefResponse, err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = safego.NewPanicErr(panicErr, debug.Stack())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrConversationOfAppOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
|
||||
}
|
||||
}()
|
||||
var (
|
||||
appID = mustParseInt64(req.GetProjectID())
|
||||
templateID = mustParseInt64(req.GetUniqueID())
|
||||
)
|
||||
if err := checkUserSpace(ctx, ctxutil.MustGetUIDFromCtx(ctx), mustParseInt64(req.GetSpaceID())); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.GetCheckOnly() {
|
||||
wfs, err := GetWorkflowDomainSVC().CheckWorkflowsToReplace(ctx, appID, templateID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = &workflow.DeleteProjectConversationDefResponse{NeedReplace: make([]*workflow.Workflow, 0)}
|
||||
for _, wf := range wfs {
|
||||
resp.NeedReplace = append(resp.NeedReplace, &workflow.Workflow{
|
||||
Name: wf.Name,
|
||||
URL: wf.IconURL,
|
||||
WorkflowID: strconv.FormatInt(wf.ID, 10),
|
||||
})
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
wfID2ConversationName, err := maps.TransformKeyWithErrorCheck(req.GetReplace(), func(k1 string) (int64, error) {
|
||||
return strconv.ParseInt(k1, 10, 64)
|
||||
})
|
||||
|
||||
rowsAffected, err := GetWorkflowDomainSVC().DeleteDraftConversationTemplate(ctx, templateID, wfID2ConversationName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rowsAffected > 0 {
|
||||
return &workflow.DeleteProjectConversationDefResponse{
|
||||
Success: true,
|
||||
}, err
|
||||
}
|
||||
|
||||
rowsAffected, err = GetWorkflowDomainSVC().DeleteDynamicConversation(ctx, vo.Draft, templateID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rowsAffected == 0 {
|
||||
return nil, fmt.Errorf("delete conversation failed")
|
||||
}
|
||||
|
||||
return &workflow.DeleteProjectConversationDefResponse{
|
||||
Success: true,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (w *ApplicationService) ListApplicationConversationDef(ctx context.Context, req *workflow.ListProjectConversationRequest) (resp *workflow.ListProjectConversationResponse, err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = safego.NewPanicErr(panicErr, debug.Stack())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrConversationOfAppOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
|
||||
}
|
||||
}()
|
||||
var connectorID int64
|
||||
if len(req.GetConnectorID()) != 0 {
|
||||
connectorID = mustParseInt64(req.GetConnectorID())
|
||||
} else {
|
||||
connectorID = consts.CozeConnectorID
|
||||
}
|
||||
var (
|
||||
page = mustParseInt64(ternary.IFElse(req.GetCursor() == "", "0", req.GetCursor()))
|
||||
size = req.GetLimit()
|
||||
userID = ctxutil.MustGetUIDFromCtx(ctx)
|
||||
spaceID = mustParseInt64(req.GetSpaceID())
|
||||
appID = mustParseInt64(req.GetProjectID())
|
||||
version = req.ProjectVersion
|
||||
listConversationMeta = vo.ListConversationMeta{
|
||||
APPID: appID,
|
||||
UserID: userID,
|
||||
ConnectorID: connectorID,
|
||||
}
|
||||
)
|
||||
|
||||
if err := checkUserSpace(ctx, userID, spaceID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
env := ternary.IFElse(req.GetCreateEnv() == workflow.CreateEnv_Draft, vo.Draft, vo.Online)
|
||||
if req.GetCreateMethod() == workflow.CreateMethod_ManualCreate {
|
||||
templates, err := GetWorkflowDomainSVC().ListConversationTemplate(ctx, env, &vo.ListConversationTemplatePolicy{
|
||||
AppID: appID,
|
||||
Page: &vo.Page{
|
||||
Page: int32(page),
|
||||
Size: int32(size),
|
||||
},
|
||||
NameLike: ternary.IFElse(len(req.GetNameLike()) == 0, nil, ptr.Of(req.GetNameLike())),
|
||||
Version: version,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stsConversations, err := GetWorkflowDomainSVC().MGetStaticConversation(ctx, env, userID, connectorID, slices.Transform(templates, func(a *entity.ConversationTemplate) int64 {
|
||||
return a.TemplateID
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stsConversationMap := slices.ToMap(stsConversations, func(e *entity.StaticConversation) (int64, *entity.StaticConversation) {
|
||||
return e.TemplateID, e
|
||||
})
|
||||
|
||||
resp = &workflow.ListProjectConversationResponse{Data: make([]*workflow.ProjectConversation, 0)}
|
||||
for _, tmpl := range templates {
|
||||
conversationID := ""
|
||||
if c, ok := stsConversationMap[tmpl.TemplateID]; ok {
|
||||
conversationID = strconv.FormatInt(c.ConversationID, 10)
|
||||
}
|
||||
resp.Data = append(resp.Data, &workflow.ProjectConversation{
|
||||
UniqueID: strconv.FormatInt(tmpl.TemplateID, 10),
|
||||
ConversationName: tmpl.Name,
|
||||
ConversationID: conversationID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if req.GetCreateMethod() == workflow.CreateMethod_NodeCreate {
|
||||
dyConversations, err := GetWorkflowDomainSVC().ListDynamicConversation(ctx, env, &vo.ListConversationPolicy{
|
||||
ListConversationMeta: listConversationMeta,
|
||||
Page: &vo.Page{
|
||||
Page: int32(page),
|
||||
Size: int32(size),
|
||||
},
|
||||
NameLike: ternary.IFElse(len(req.GetNameLike()) == 0, nil, ptr.Of(req.GetNameLike())),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = &workflow.ListProjectConversationResponse{Data: make([]*workflow.ProjectConversation, 0, len(dyConversations))}
|
||||
resp.Data = append(resp.Data, slices.Transform(dyConversations, func(a *entity.DynamicConversation) *workflow.ProjectConversation {
|
||||
return &workflow.ProjectConversation{
|
||||
UniqueID: strconv.FormatInt(a.ID, 10),
|
||||
ConversationName: a.Name,
|
||||
ConversationID: strconv.FormatInt(a.ConversationID, 10),
|
||||
}
|
||||
})...)
|
||||
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@ -17,10 +17,12 @@
|
||||
package workflow
|
||||
|
||||
import (
|
||||
"github.com/cloudwego/eino/callbacks"
|
||||
"github.com/cloudwego/eino/compose"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"gorm.io/gorm"
|
||||
|
||||
wfconversation "github.com/coze-dev/coze-studio/backend/crossdomain/workflow/conversation"
|
||||
wfdatabase "github.com/coze-dev/coze-studio/backend/crossdomain/workflow/database"
|
||||
wfknowledge "github.com/coze-dev/coze-studio/backend/crossdomain/workflow/knowledge"
|
||||
wfmodel "github.com/coze-dev/coze-studio/backend/crossdomain/workflow/model"
|
||||
@ -34,6 +36,7 @@ import (
|
||||
search "github.com/coze-dev/coze-studio/backend/domain/search/service"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
crosscode "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/code"
|
||||
crossconversation "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
crossdatabase "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/database"
|
||||
crossknowledge "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/knowledge"
|
||||
crossmodel "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/model"
|
||||
@ -41,6 +44,7 @@ import (
|
||||
crosssearch "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/search"
|
||||
crossvariable "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/variable"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/service"
|
||||
workflowservice "github.com/coze-dev/coze-studio/backend/domain/workflow/service"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/coderunner"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/imagex"
|
||||
@ -78,6 +82,8 @@ func InitService(components *ServiceComponents) *ApplicationService {
|
||||
crossmodel.SetManager(wfmodel.NewModelManager(components.ModelManager, nil))
|
||||
crosscode.SetCodeRunner(components.CodeRunner)
|
||||
crosssearch.SetNotifier(wfsearch.NewNotify(components.DomainNotifier))
|
||||
crossconversation.SetConversationManager(wfconversation.NewConversationRepository())
|
||||
callbacks.AppendGlobalHandlers(workflowservice.GetTokenCallbackHandler())
|
||||
|
||||
SVC.DomainSVC = workflowDomainSVC
|
||||
SVC.ImageX = components.ImageX
|
||||
|
||||
@ -93,7 +93,7 @@ func (w *ApplicationService) GetNodeTemplateList(ctx context.Context, req *workf
|
||||
|
||||
toQueryTypes := make(map[entity.NodeType]bool)
|
||||
for _, t := range req.NodeTypes {
|
||||
entityType, err := nodeType2EntityNodeType(t)
|
||||
entityType, err := entity.BlockType2EntityNodeType(t)
|
||||
if err != nil {
|
||||
logs.Warnf("get node type %v failed, err:=%v", t, err)
|
||||
continue
|
||||
@ -116,7 +116,7 @@ func (w *ApplicationService) GetNodeTemplateList(ctx context.Context, req *workf
|
||||
Name: category,
|
||||
}
|
||||
for _, nodeMeta := range nodeMetaList {
|
||||
tplType, err := entityNodeTypeToAPINodeTemplateType(nodeMeta.Type)
|
||||
tplType, err := entity.NodeTypeToAPINodeTemplateType(nodeMeta.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -169,6 +169,21 @@ func (w *ApplicationService) CreateWorkflow(ctx context.Context, req *workflow.C
|
||||
if err := checkUserSpace(ctx, uID, spaceID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var createConversation bool
|
||||
if req.ProjectID != nil && req.IsSetFlowMode() && req.GetFlowMode() == workflow.WorkflowMode_ChatFlow && req.IsSetCreateConversation() && req.GetCreateConversation() {
|
||||
createConversation = true
|
||||
_, err := GetWorkflowDomainSVC().CreateDraftConversationTemplate(ctx, &vo.CreateConversationTemplateMeta{
|
||||
AppID: mustParseInt64(req.GetProjectID()),
|
||||
UserID: uID,
|
||||
SpaceID: spaceID,
|
||||
Name: req.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
wf := &vo.MetaCreate{
|
||||
CreatorID: uID,
|
||||
SpaceID: spaceID,
|
||||
@ -180,6 +195,13 @@ func (w *ApplicationService) CreateWorkflow(ctx context.Context, req *workflow.C
|
||||
Mode: ternary.IFElse(req.IsSetFlowMode(), req.GetFlowMode(), workflow.WorkflowMode_Workflow),
|
||||
InitCanvasSchema: entity.GetDefaultInitCanvasJsonSchema(i18n.GetLocale(ctx)),
|
||||
}
|
||||
if req.IsSetFlowMode() && req.GetFlowMode() == workflow.WorkflowMode_ChatFlow {
|
||||
conversationName := req.Name
|
||||
if !req.IsSetProjectID() || mustParseInt64(req.GetProjectID()) == 0 || !createConversation {
|
||||
conversationName = "Default"
|
||||
}
|
||||
wf.InitCanvasSchema = entity.GetDefaultInitCanvasJsonSchemaChat(i18n.GetLocale(ctx), conversationName)
|
||||
}
|
||||
|
||||
id, err := GetWorkflowDomainSVC().Create(ctx, wf)
|
||||
if err != nil {
|
||||
@ -1034,6 +1056,18 @@ func (w *ApplicationService) CopyWorkflowFromLibraryToApp(ctx context.Context, w
|
||||
wf, err := GetWorkflowDomainSVC().CopyWorkflow(ctx, workflowID, vo.CopyWorkflowPolicy{
|
||||
TargetAppID: &appID,
|
||||
})
|
||||
|
||||
if wf.Mode == workflow.WorkflowMode_ChatFlow {
|
||||
err = GetWorkflowDomainSVC().CopyChatFlowRole(ctx, &vo.CopyRolePolicy{
|
||||
SourceID: workflowID,
|
||||
TargetID: wf.ID,
|
||||
CreatorID: wf.CreatorID,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -1127,7 +1161,7 @@ func (w *ApplicationService) MoveWorkflowFromAppToLibrary(ctx context.Context, w
|
||||
}
|
||||
|
||||
func convertNodeExecution(nodeExe *entity.NodeExecution) (*workflow.NodeResult, error) {
|
||||
nType, err := entityNodeTypeToAPINodeTemplateType(nodeExe.NodeType)
|
||||
nType, err := entity.NodeTypeToAPINodeTemplateType(nodeExe.NodeType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1317,7 +1351,7 @@ func convertStreamRunEvent(workflowID int64) func(msg *entity.Message) (res *wor
|
||||
}
|
||||
|
||||
var nodeType workflow.NodeTemplateType
|
||||
nodeType, err = entityNodeTypeToAPINodeTemplateType(msg.NodeType)
|
||||
nodeType, err = entity.NodeTypeToAPINodeTemplateType(msg.NodeType)
|
||||
if err != nil {
|
||||
logs.Errorf("convert node type %v failed, err:=%v", msg.NodeType, err)
|
||||
nodeType = workflow.NodeTemplateType(0)
|
||||
@ -2087,6 +2121,11 @@ func (w *ApplicationService) ListWorkflow(ctx context.Context, req *workflow.Get
|
||||
},
|
||||
}
|
||||
|
||||
ww.CheckResult, err = GetWorkflowDomainSVC().WorkflowSchemaCheck(ctx, w, req.Checker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if qType == vo.FromDraft {
|
||||
ww.UpdateTime = w.DraftMeta.Timestamp.Unix()
|
||||
} else if qType == vo.FromLatestVersion || qType == vo.FromSpecificVersion {
|
||||
@ -3338,178 +3377,6 @@ func toWorkflowParameter(nType *vo.NamedTypeInfo) (*workflow.Parameter, error) {
|
||||
return wp, nil
|
||||
}
|
||||
|
||||
func nodeType2EntityNodeType(t string) (entity.NodeType, error) {
|
||||
i, err := strconv.Atoi(t)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid node type string '%s': %w", t, err)
|
||||
}
|
||||
|
||||
switch i {
|
||||
case 1:
|
||||
return entity.NodeTypeEntry, nil
|
||||
case 2:
|
||||
return entity.NodeTypeExit, nil
|
||||
case 3:
|
||||
return entity.NodeTypeLLM, nil
|
||||
case 4:
|
||||
return entity.NodeTypePlugin, nil
|
||||
case 5:
|
||||
return entity.NodeTypeCodeRunner, nil
|
||||
case 6:
|
||||
return entity.NodeTypeKnowledgeRetriever, nil
|
||||
case 8:
|
||||
return entity.NodeTypeSelector, nil
|
||||
case 9:
|
||||
return entity.NodeTypeSubWorkflow, nil
|
||||
case 12:
|
||||
return entity.NodeTypeDatabaseCustomSQL, nil
|
||||
case 13:
|
||||
return entity.NodeTypeOutputEmitter, nil
|
||||
case 15:
|
||||
return entity.NodeTypeTextProcessor, nil
|
||||
case 18:
|
||||
return entity.NodeTypeQuestionAnswer, nil
|
||||
case 19:
|
||||
return entity.NodeTypeBreak, nil
|
||||
case 20:
|
||||
return entity.NodeTypeVariableAssignerWithinLoop, nil
|
||||
case 21:
|
||||
return entity.NodeTypeLoop, nil
|
||||
case 22:
|
||||
return entity.NodeTypeIntentDetector, nil
|
||||
case 27:
|
||||
return entity.NodeTypeKnowledgeIndexer, nil
|
||||
case 28:
|
||||
return entity.NodeTypeBatch, nil
|
||||
case 29:
|
||||
return entity.NodeTypeContinue, nil
|
||||
case 30:
|
||||
return entity.NodeTypeInputReceiver, nil
|
||||
case 32:
|
||||
return entity.NodeTypeVariableAggregator, nil
|
||||
case 37:
|
||||
return entity.NodeTypeMessageList, nil
|
||||
case 38:
|
||||
return entity.NodeTypeClearMessage, nil
|
||||
case 39:
|
||||
return entity.NodeTypeCreateConversation, nil
|
||||
case 40:
|
||||
return entity.NodeTypeVariableAssigner, nil
|
||||
case 42:
|
||||
return entity.NodeTypeDatabaseUpdate, nil
|
||||
case 43:
|
||||
return entity.NodeTypeDatabaseQuery, nil
|
||||
case 44:
|
||||
return entity.NodeTypeDatabaseDelete, nil
|
||||
case 45:
|
||||
return entity.NodeTypeHTTPRequester, nil
|
||||
case 46:
|
||||
return entity.NodeTypeDatabaseInsert, nil
|
||||
case 58:
|
||||
return entity.NodeTypeJsonSerialization, nil
|
||||
case 59:
|
||||
return entity.NodeTypeJsonDeserialization, nil
|
||||
case 60:
|
||||
return entity.NodeTypeKnowledgeDeleter, nil
|
||||
default:
|
||||
// Handle all unknown or unsupported types here
|
||||
return "", fmt.Errorf("unsupported or unknown node type ID: %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
// entityNodeTypeToAPINodeTemplateType converts an entity.NodeType to the corresponding workflow.NodeTemplateType.
|
||||
func entityNodeTypeToAPINodeTemplateType(nodeType entity.NodeType) (workflow.NodeTemplateType, error) {
|
||||
switch nodeType {
|
||||
case entity.NodeTypeEntry:
|
||||
return workflow.NodeTemplateType_Start, nil
|
||||
case entity.NodeTypeExit:
|
||||
return workflow.NodeTemplateType_End, nil
|
||||
case entity.NodeTypeLLM:
|
||||
return workflow.NodeTemplateType_LLM, nil
|
||||
case entity.NodeTypePlugin:
|
||||
// Maps to Api type in the API model
|
||||
return workflow.NodeTemplateType_Api, nil
|
||||
case entity.NodeTypeCodeRunner:
|
||||
return workflow.NodeTemplateType_Code, nil
|
||||
case entity.NodeTypeKnowledgeRetriever:
|
||||
// Maps to Dataset type in the API model
|
||||
return workflow.NodeTemplateType_Dataset, nil
|
||||
case entity.NodeTypeSelector:
|
||||
// Maps to If type in the API model
|
||||
return workflow.NodeTemplateType_If, nil
|
||||
case entity.NodeTypeSubWorkflow:
|
||||
return workflow.NodeTemplateType_SubWorkflow, nil
|
||||
case entity.NodeTypeDatabaseCustomSQL:
|
||||
// Maps to the generic Database type in the API model
|
||||
return workflow.NodeTemplateType_Database, nil
|
||||
case entity.NodeTypeOutputEmitter:
|
||||
// Maps to Message type in the API model
|
||||
return workflow.NodeTemplateType_Message, nil
|
||||
case entity.NodeTypeTextProcessor:
|
||||
return workflow.NodeTemplateType_Text, nil
|
||||
case entity.NodeTypeQuestionAnswer:
|
||||
return workflow.NodeTemplateType_Question, nil
|
||||
case entity.NodeTypeBreak:
|
||||
return workflow.NodeTemplateType_Break, nil
|
||||
case entity.NodeTypeVariableAssigner:
|
||||
return workflow.NodeTemplateType_AssignVariable, nil
|
||||
case entity.NodeTypeVariableAssignerWithinLoop:
|
||||
return workflow.NodeTemplateType_LoopSetVariable, nil
|
||||
case entity.NodeTypeLoop:
|
||||
return workflow.NodeTemplateType_Loop, nil
|
||||
case entity.NodeTypeIntentDetector:
|
||||
return workflow.NodeTemplateType_Intent, nil
|
||||
case entity.NodeTypeKnowledgeIndexer:
|
||||
// Maps to DatasetWrite type in the API model
|
||||
return workflow.NodeTemplateType_DatasetWrite, nil
|
||||
case entity.NodeTypeBatch:
|
||||
return workflow.NodeTemplateType_Batch, nil
|
||||
case entity.NodeTypeContinue:
|
||||
return workflow.NodeTemplateType_Continue, nil
|
||||
case entity.NodeTypeInputReceiver:
|
||||
return workflow.NodeTemplateType_Input, nil
|
||||
case entity.NodeTypeMessageList:
|
||||
return workflow.NodeTemplateType(37), nil
|
||||
case entity.NodeTypeVariableAggregator:
|
||||
return workflow.NodeTemplateType(32), nil
|
||||
case entity.NodeTypeClearMessage:
|
||||
return workflow.NodeTemplateType(38), nil
|
||||
case entity.NodeTypeCreateConversation:
|
||||
return workflow.NodeTemplateType(39), nil
|
||||
// Note: entity.NodeTypeVariableAggregator (ID 32) has no direct mapping in NodeTemplateType
|
||||
// Note: entity.NodeTypeMessageList (ID 37) has no direct mapping in NodeTemplateType
|
||||
// Note: entity.NodeTypeClearMessage (ID 38) has no direct mapping in NodeTemplateType
|
||||
// Note: entity.NodeTypeCreateConversation (ID 39) has no direct mapping in NodeTemplateType
|
||||
case entity.NodeTypeDatabaseUpdate:
|
||||
return workflow.NodeTemplateType_DatabaseUpdate, nil
|
||||
case entity.NodeTypeDatabaseQuery:
|
||||
// Maps to DatabasesELECT (ID 43) in the API model (note potential typo)
|
||||
return workflow.NodeTemplateType_DatabasesELECT, nil
|
||||
case entity.NodeTypeDatabaseDelete:
|
||||
return workflow.NodeTemplateType_DatabaseDelete, nil
|
||||
|
||||
// Note: entity.NodeTypeHTTPRequester (ID 45) has no direct mapping in NodeTemplateType
|
||||
case entity.NodeTypeHTTPRequester:
|
||||
return workflow.NodeTemplateType(45), nil
|
||||
|
||||
case entity.NodeTypeDatabaseInsert:
|
||||
// Maps to DatabaseInsert (ID 41) in the API model, despite entity ID being 46.
|
||||
// return workflow.NodeTemplateType_DatabaseInsert, nil
|
||||
return workflow.NodeTemplateType(46), nil
|
||||
case entity.NodeTypeJsonSerialization:
|
||||
return workflow.NodeTemplateType_JsonSerialization, nil
|
||||
case entity.NodeTypeJsonDeserialization:
|
||||
return workflow.NodeTemplateType_JsonDeserialization, nil
|
||||
case entity.NodeTypeKnowledgeDeleter:
|
||||
return workflow.NodeTemplateType_DatasetDelete, nil
|
||||
case entity.NodeTypeLambda:
|
||||
return 0, nil
|
||||
default:
|
||||
// Handle entity types that don't have a corresponding NodeTemplateType
|
||||
return workflow.NodeTemplateType(0), fmt.Errorf("cannot map entity node type '%s' to a workflow.NodeTemplateType", nodeType)
|
||||
}
|
||||
}
|
||||
|
||||
func i64PtrToStringPtr(i *int64) *string {
|
||||
if i == nil {
|
||||
return nil
|
||||
@ -3813,3 +3680,357 @@ func checkUserSpace(ctx context.Context, uid int64, spaceID int64) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *ApplicationService) populateChatFlowRoleFields(role *workflow.ChatFlowRole, targetRole interface{}) error {
|
||||
var avatarUri, audioStr, bgStr, obStr, srStr, uiStr string
|
||||
var err error
|
||||
|
||||
if role.Avatar != nil {
|
||||
avatarUri = role.Avatar.ImageUri
|
||||
|
||||
}
|
||||
if role.AudioConfig != nil {
|
||||
audioStr, err = sonic.MarshalString(*role.AudioConfig)
|
||||
if err != nil {
|
||||
return vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
}
|
||||
if role.BackgroundImageInfo != nil {
|
||||
bgStr, err = sonic.MarshalString(*role.BackgroundImageInfo)
|
||||
if err != nil {
|
||||
return vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
}
|
||||
if role.OnboardingInfo != nil {
|
||||
obStr, err = sonic.MarshalString(*role.OnboardingInfo)
|
||||
if err != nil {
|
||||
return vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
}
|
||||
if role.SuggestReplyInfo != nil {
|
||||
srStr, err = sonic.MarshalString(*role.SuggestReplyInfo)
|
||||
if err != nil {
|
||||
return vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
}
|
||||
if role.UserInputConfig != nil {
|
||||
uiStr, err = sonic.MarshalString(*role.UserInputConfig)
|
||||
if err != nil {
|
||||
return vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
}
|
||||
|
||||
switch r := targetRole.(type) {
|
||||
case *vo.ChatFlowRoleCreate:
|
||||
if role.Name != nil {
|
||||
r.Name = *role.Name
|
||||
}
|
||||
if role.Description != nil {
|
||||
r.Description = *role.Description
|
||||
}
|
||||
if avatarUri != "" {
|
||||
r.AvatarUri = avatarUri
|
||||
}
|
||||
if audioStr != "" {
|
||||
r.AudioConfig = audioStr
|
||||
}
|
||||
if bgStr != "" {
|
||||
r.BackgroundImageInfo = bgStr
|
||||
}
|
||||
if obStr != "" {
|
||||
r.OnboardingInfo = obStr
|
||||
}
|
||||
if srStr != "" {
|
||||
r.SuggestReplyInfo = srStr
|
||||
}
|
||||
if uiStr != "" {
|
||||
r.UserInputConfig = uiStr
|
||||
}
|
||||
case *vo.ChatFlowRoleUpdate:
|
||||
r.Name = role.Name
|
||||
r.Description = role.Description
|
||||
if avatarUri != "" {
|
||||
r.AvatarUri = ptr.Of(avatarUri)
|
||||
}
|
||||
if audioStr != "" {
|
||||
r.AudioConfig = ptr.Of(audioStr)
|
||||
}
|
||||
if bgStr != "" {
|
||||
r.BackgroundImageInfo = ptr.Of(bgStr)
|
||||
}
|
||||
if obStr != "" {
|
||||
r.OnboardingInfo = ptr.Of(obStr)
|
||||
}
|
||||
if srStr != "" {
|
||||
r.SuggestReplyInfo = ptr.Of(srStr)
|
||||
}
|
||||
if uiStr != "" {
|
||||
r.UserInputConfig = ptr.Of(uiStr)
|
||||
}
|
||||
default:
|
||||
return vo.WrapError(errno.ErrInvalidParameter, fmt.Errorf("invalid type for targetRole: %T", targetRole))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsChatFlow(wf *entity.Workflow) bool {
|
||||
if wf == nil || wf.ID == 0 {
|
||||
return false
|
||||
}
|
||||
return wf.Meta.Mode == workflow.WorkflowMode_ChatFlow
|
||||
}
|
||||
|
||||
func (w *ApplicationService) CreateChatFlowRole(ctx context.Context, req *workflow.CreateChatFlowRoleRequest) (
|
||||
_ *workflow.CreateChatFlowRoleResponse, err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = safego.NewPanicErr(panicErr, debug.Stack())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrChatFlowRoleOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
|
||||
}
|
||||
}()
|
||||
|
||||
uID := ctxutil.MustGetUIDFromCtx(ctx)
|
||||
wf, err := GetWorkflowDomainSVC().Get(ctx, &vo.GetPolicy{
|
||||
ID: mustParseInt64(req.GetChatFlowRole().GetWorkflowID()),
|
||||
MetaOnly: true,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = checkUserSpace(ctx, uID, wf.Meta.SpaceID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
role := req.GetChatFlowRole()
|
||||
|
||||
if !IsChatFlow(wf) {
|
||||
logs.CtxWarnf(ctx, "CreateChatFlowRole not chat flow, workflowID: %d", wf.ID)
|
||||
return nil, vo.WrapError(errno.ErrChatFlowRoleOperationFail, fmt.Errorf("workflow %d is not a chat flow", wf.ID))
|
||||
}
|
||||
|
||||
oldRole, err := GetWorkflowDomainSVC().GetChatFlowRole(ctx, mustParseInt64(role.WorkflowID), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var roleID int64
|
||||
if oldRole != nil {
|
||||
role.ID = strconv.FormatInt(oldRole.ID, 10)
|
||||
roleID = oldRole.ID
|
||||
}
|
||||
|
||||
if role.GetID() == "" || role.GetID() == "0" {
|
||||
chatFlowRole := &vo.ChatFlowRoleCreate{
|
||||
WorkflowID: mustParseInt64(role.WorkflowID),
|
||||
CreatorID: uID,
|
||||
}
|
||||
if err = w.populateChatFlowRoleFields(role, chatFlowRole); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roleID, err = GetWorkflowDomainSVC().CreateChatFlowRole(ctx, chatFlowRole)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
chatFlowRole := &vo.ChatFlowRoleUpdate{
|
||||
WorkflowID: mustParseInt64(role.WorkflowID),
|
||||
}
|
||||
|
||||
if err = w.populateChatFlowRoleFields(role, chatFlowRole); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = GetWorkflowDomainSVC().UpdateChatFlowRole(ctx, chatFlowRole.WorkflowID, chatFlowRole)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &workflow.CreateChatFlowRoleResponse{
|
||||
ID: strconv.FormatInt(roleID, 10),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *ApplicationService) DeleteChatFlowRole(ctx context.Context, req *workflow.DeleteChatFlowRoleRequest) (
|
||||
_ *workflow.DeleteChatFlowRoleResponse, err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = safego.NewPanicErr(panicErr, debug.Stack())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrChatFlowRoleOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
|
||||
}
|
||||
}()
|
||||
|
||||
uID := ctxutil.MustGetUIDFromCtx(ctx)
|
||||
wf, err := GetWorkflowDomainSVC().Get(ctx, &vo.GetPolicy{
|
||||
ID: mustParseInt64(req.GetWorkflowID()),
|
||||
MetaOnly: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = checkUserSpace(ctx, uID, wf.Meta.SpaceID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = GetWorkflowDomainSVC().DeleteChatFlowRole(ctx, mustParseInt64(req.ID), mustParseInt64(req.WorkflowID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &workflow.DeleteChatFlowRoleResponse{}, nil
|
||||
}
|
||||
|
||||
func (w *ApplicationService) GetChatFlowRole(ctx context.Context, req *workflow.GetChatFlowRoleRequest) (
|
||||
_ *workflow.GetChatFlowRoleResponse, err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = safego.NewPanicErr(panicErr, debug.Stack())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrChatFlowRoleOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
|
||||
}
|
||||
}()
|
||||
|
||||
uID := ctxutil.MustGetUIDFromCtx(ctx)
|
||||
wf, err := GetWorkflowDomainSVC().Get(ctx, &vo.GetPolicy{
|
||||
ID: mustParseInt64(req.GetWorkflowID()),
|
||||
MetaOnly: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = checkUserSpace(ctx, uID, wf.Meta.SpaceID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !IsChatFlow(wf) {
|
||||
logs.CtxWarnf(ctx, "GetChatFlowRole not chat flow, workflowID: %d", wf.ID)
|
||||
return nil, vo.WrapError(errno.ErrChatFlowRoleOperationFail, fmt.Errorf("workflow %d is not a chat flow", wf.ID))
|
||||
}
|
||||
|
||||
var version string
|
||||
if wf.Meta.AppID != nil {
|
||||
vl, err := GetWorkflowDomainSVC().GetWorkflowVersionsByConnector(ctx, mustParseInt64(req.GetConnectorID()), wf.ID, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(vl) > 0 {
|
||||
version = vl[0]
|
||||
}
|
||||
}
|
||||
|
||||
role, err := GetWorkflowDomainSVC().GetChatFlowRole(ctx, mustParseInt64(req.WorkflowID), version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if role == nil {
|
||||
logs.CtxWarnf(ctx, "GetChatFlowRole role nil, workflowID: %d", wf.ID)
|
||||
// Return nil for the error to align with the production behavior,
|
||||
// where the GET API may be called before the CREATE API during chatflow creation.
|
||||
return &workflow.GetChatFlowRoleResponse{}, nil
|
||||
}
|
||||
|
||||
wfRole, err := w.convertChatFlowRole(ctx, role)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get chat flow role config, internal data processing error: %+v", err)
|
||||
}
|
||||
|
||||
return &workflow.GetChatFlowRoleResponse{
|
||||
Role: wfRole,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *ApplicationService) convertChatFlowRole(ctx context.Context, role *entity.ChatFlowRole) (*workflow.ChatFlowRole, error) {
|
||||
var err error
|
||||
res := &workflow.ChatFlowRole{
|
||||
ID: strconv.FormatInt(role.ID, 10),
|
||||
WorkflowID: strconv.FormatInt(role.WorkflowID, 10),
|
||||
Name: ptr.Of(role.Name),
|
||||
Description: ptr.Of(role.Description),
|
||||
}
|
||||
|
||||
if role.AvatarUri != "" {
|
||||
url, err := w.ImageX.GetResourceURL(ctx, role.AvatarUri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.Avatar = &workflow.AvatarConfig{
|
||||
ImageUri: role.AvatarUri,
|
||||
ImageUrl: url.URL,
|
||||
}
|
||||
}
|
||||
|
||||
if role.AudioConfig != "" {
|
||||
err = sonic.UnmarshalString(role.AudioConfig, &res.AudioConfig)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "GetChatFlowRole AudioConfig UnmarshalString err: %+v", err)
|
||||
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
}
|
||||
|
||||
if role.OnboardingInfo != "" {
|
||||
err = sonic.UnmarshalString(role.OnboardingInfo, &res.OnboardingInfo)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "GetChatFlowRole OnboardingInfo UnmarshalString err: %+v", err)
|
||||
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
}
|
||||
|
||||
if role.SuggestReplyInfo != "" {
|
||||
err = sonic.UnmarshalString(role.SuggestReplyInfo, &res.SuggestReplyInfo)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "GetChatFlowRole SuggestReplyInfo UnmarshalString err: %+v", err)
|
||||
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
}
|
||||
|
||||
if role.UserInputConfig != "" {
|
||||
err = sonic.UnmarshalString(role.UserInputConfig, &res.UserInputConfig)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "GetChatFlowRole UserInputConfig UnmarshalString err: %+v", err)
|
||||
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
}
|
||||
|
||||
if role.BackgroundImageInfo != "" {
|
||||
res.BackgroundImageInfo = &workflow.BackgroundImageInfo{}
|
||||
err = sonic.UnmarshalString(role.BackgroundImageInfo, res.BackgroundImageInfo)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "GetChatFlowRole BackgroundImageInfo UnmarshalString err: %+v", err)
|
||||
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
if res.BackgroundImageInfo != nil {
|
||||
if res.BackgroundImageInfo.WebBackgroundImage != nil && res.BackgroundImageInfo.WebBackgroundImage.OriginImageUri != nil {
|
||||
url, err := w.ImageX.GetResourceURL(ctx, res.BackgroundImageInfo.WebBackgroundImage.GetOriginImageUri())
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "get url by uri err, err:%s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
res.BackgroundImageInfo.WebBackgroundImage.ImageUrl = &url.URL
|
||||
}
|
||||
|
||||
if res.BackgroundImageInfo.MobileBackgroundImage != nil && res.BackgroundImageInfo.MobileBackgroundImage.OriginImageUri != nil {
|
||||
url, err := w.ImageX.GetResourceURL(ctx, res.BackgroundImageInfo.MobileBackgroundImage.GetOriginImageUri())
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "get url by uri err, err:%s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
res.BackgroundImageInfo.MobileBackgroundImage.ImageUrl = &url.URL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ meta:
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai:
|
||||
by_azure: true
|
||||
by_azure: false
|
||||
api_version: ""
|
||||
response_format:
|
||||
type: text
|
||||
|
||||
@ -20,10 +20,13 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/conversation/conversation/entity"
|
||||
)
|
||||
|
||||
type Conversation interface {
|
||||
GetCurrentConversation(ctx context.Context, req *conversation.GetCurrent) (*conversation.Conversation, error)
|
||||
Create(ctx context.Context, req *entity.CreateMeta) (*entity.Conversation, error)
|
||||
NewConversationCtx(ctx context.Context, req *entity.NewConversationCtxRequest) (*entity.NewConversationCtxResponse, error)
|
||||
}
|
||||
|
||||
var defaultSVC Conversation
|
||||
|
||||
@ -20,13 +20,16 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/conversation/message/entity"
|
||||
)
|
||||
|
||||
type Message interface {
|
||||
GetByRunIDs(ctx context.Context, conversationID int64, runIDs []int64) ([]*message.Message, error)
|
||||
PreCreate(ctx context.Context, msg *message.Message) (*message.Message, error)
|
||||
Create(ctx context.Context, msg *message.Message) (*message.Message, error)
|
||||
List(ctx context.Context, meta *entity.ListMeta) (*entity.ListResult, error)
|
||||
Edit(ctx context.Context, msg *message.Message) (*message.Message, error)
|
||||
Delete(ctx context.Context, req *entity.DeleteMeta) error
|
||||
}
|
||||
|
||||
var defaultSVC Message
|
||||
|
||||
@ -20,8 +20,10 @@ import (
|
||||
"context"
|
||||
|
||||
einoCompose "github.com/cloudwego/eino/compose"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
|
||||
workflowEntity "github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
)
|
||||
@ -37,10 +39,13 @@ type Workflow interface {
|
||||
GetWorkflowIDsByAppID(ctx context.Context, appID int64) ([]int64, error)
|
||||
SyncExecuteWorkflow(ctx context.Context, config vo.ExecuteConfig, input map[string]any) (*workflowEntity.WorkflowExecution, vo.TerminatePlan, error)
|
||||
WithExecuteConfig(cfg vo.ExecuteConfig) einoCompose.Option
|
||||
StreamExecute(ctx context.Context, config vo.ExecuteConfig, input map[string]any) (*schema.StreamReader[*workflowEntity.Message], error)
|
||||
InitApplicationDefaultConversationTemplate(ctx context.Context, spaceID int64, appID int64, userID int64) error
|
||||
}
|
||||
|
||||
type ExecuteConfig = vo.ExecuteConfig
|
||||
type ExecuteMode = vo.ExecuteMode
|
||||
type WorkflowMessage = workflowEntity.Message
|
||||
|
||||
const (
|
||||
ExecuteModeDebug ExecuteMode = "debug"
|
||||
|
||||
@ -21,6 +21,7 @@ import (
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossconversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/conversation/conversation/entity"
|
||||
conversation "github.com/coze-dev/coze-studio/backend/domain/conversation/conversation/service"
|
||||
)
|
||||
|
||||
@ -40,3 +41,11 @@ func InitDomainService(c conversation.Conversation) crossconversation.Conversati
|
||||
func (s *impl) GetCurrentConversation(ctx context.Context, req *model.GetCurrent) (*model.Conversation, error) {
|
||||
return s.DomainSVC.GetCurrentConversation(ctx, req)
|
||||
}
|
||||
|
||||
func (s *impl) Create(ctx context.Context, req *entity.CreateMeta) (*entity.Conversation, error) {
|
||||
return s.DomainSVC.Create(ctx, req)
|
||||
}
|
||||
|
||||
func (s *impl) NewConversationCtx(ctx context.Context, req *entity.NewConversationCtxRequest) (*entity.NewConversationCtxResponse, error) {
|
||||
return s.DomainSVC.NewConversationCtx(ctx, req)
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ import (
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossmessage"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/conversation/message/entity"
|
||||
message "github.com/coze-dev/coze-studio/backend/domain/conversation/message/service"
|
||||
)
|
||||
|
||||
@ -53,3 +54,11 @@ func (c *impl) Edit(ctx context.Context, msg *model.Message) (*model.Message, er
|
||||
func (c *impl) PreCreate(ctx context.Context, msg *model.Message) (*model.Message, error) {
|
||||
return c.DomainSVC.PreCreate(ctx, msg)
|
||||
}
|
||||
|
||||
func (c *impl) List(ctx context.Context, lm *entity.ListMeta) (*entity.ListResult, error) {
|
||||
return c.DomainSVC.List(ctx, lm)
|
||||
}
|
||||
|
||||
func (c *impl) Delete(ctx context.Context, req *entity.DeleteMeta) error {
|
||||
return c.DomainSVC.Delete(ctx, req)
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
|
||||
einoCompose "github.com/cloudwego/eino/compose"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossworkflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
@ -72,6 +73,14 @@ func (i *impl) WithExecuteConfig(cfg vo.ExecuteConfig) einoCompose.Option {
|
||||
return i.DomainSVC.WithExecuteConfig(cfg)
|
||||
}
|
||||
|
||||
func (i *impl) StreamExecute(ctx context.Context, config vo.ExecuteConfig, input map[string]any) (*schema.StreamReader[*workflowEntity.Message], error) {
|
||||
return i.DomainSVC.StreamExecute(ctx, config, input)
|
||||
}
|
||||
|
||||
func (i *impl) InitApplicationDefaultConversationTemplate(ctx context.Context, spaceID int64, appID int64, userID int64) error {
|
||||
return i.DomainSVC.InitApplicationDefaultConversationTemplate(ctx, spaceID, appID, userID)
|
||||
}
|
||||
|
||||
func (i *impl) GetWorkflowIDsByAppID(ctx context.Context, appID int64) ([]int64, error) {
|
||||
metas, _, err := i.DomainSVC.MGet(ctx, &vo.MGetPolicy{
|
||||
MetaQuery: vo.MetaQuery{
|
||||
|
||||
201
backend/crossdomain/workflow/conversation/conversation.go
Normal file
201
backend/crossdomain/workflow/conversation/conversation.go
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/conversation/common"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossconversation"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossmessage"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/conversation/conversation/entity"
|
||||
msgentity "github.com/coze-dev/coze-studio/backend/domain/conversation/message/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
)
|
||||
|
||||
type ConversationRepository struct {
|
||||
}
|
||||
|
||||
func NewConversationRepository() *ConversationRepository {
|
||||
return &ConversationRepository{}
|
||||
}
|
||||
|
||||
func (c *ConversationRepository) CreateConversation(ctx context.Context, req *conversation.CreateConversationRequest) (int64, error) {
|
||||
ret, err := crossconversation.DefaultSVC().Create(ctx, &entity.CreateMeta{
|
||||
AgentID: req.AppID,
|
||||
UserID: req.UserID,
|
||||
ConnectorID: req.ConnectorID,
|
||||
Scene: common.Scene_SceneWorkflow,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return ret.ID, nil
|
||||
}
|
||||
|
||||
func (c *ConversationRepository) CreateMessage(ctx context.Context, req *conversation.CreateMessageRequest) (int64, error) {
|
||||
msg := &message.Message{
|
||||
ConversationID: req.ConversationID,
|
||||
Role: schema.RoleType(req.Role),
|
||||
Content: req.Content,
|
||||
ContentType: message.ContentType(req.ContentType),
|
||||
UserID: strconv.FormatInt(req.UserID, 10),
|
||||
AgentID: req.AppID,
|
||||
RunID: req.RunID,
|
||||
}
|
||||
if msg.Role == "user" {
|
||||
msg.MessageType = message.MessageTypeQuestion
|
||||
} else {
|
||||
msg.MessageType = message.MessageTypeAnswer
|
||||
}
|
||||
ret, err := crossmessage.DefaultSVC().Create(ctx, msg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return ret.ID, nil
|
||||
}
|
||||
|
||||
func (c *ConversationRepository) MessageList(ctx context.Context, req *conversation.MessageListRequest) (*conversation.MessageListResponse, error) {
|
||||
lm := &msgentity.ListMeta{
|
||||
ConversationID: req.ConversationID,
|
||||
Limit: int(req.Limit), // Since the value of limit is checked inside the node, the type cast here is safe
|
||||
UserID: strconv.FormatInt(req.UserID, 10),
|
||||
AgentID: req.AppID,
|
||||
OrderBy: req.OrderBy,
|
||||
}
|
||||
if req.BeforeID != nil {
|
||||
lm.Cursor, _ = strconv.ParseInt(*req.BeforeID, 10, 64)
|
||||
lm.Direction = msgentity.ScrollPageDirectionPrev
|
||||
}
|
||||
if req.AfterID != nil {
|
||||
lm.Cursor, _ = strconv.ParseInt(*req.AfterID, 10, 64)
|
||||
lm.Direction = msgentity.ScrollPageDirectionNext
|
||||
}
|
||||
lm.Direction = msgentity.ScrollPageDirectionNext
|
||||
lr, err := crossmessage.DefaultSVC().List(ctx, lm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := &conversation.MessageListResponse{}
|
||||
|
||||
if lr.PrevCursor > 0 {
|
||||
response.FirstID = strconv.FormatInt(lr.PrevCursor, 10)
|
||||
}
|
||||
if lr.NextCursor > 0 {
|
||||
response.LastID = strconv.FormatInt(lr.NextCursor, 10)
|
||||
}
|
||||
if len(lr.Messages) == 0 {
|
||||
return response, nil
|
||||
}
|
||||
messages, err := convertMessage(lr.Messages)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.Messages = messages
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *ConversationRepository) ClearConversationHistory(ctx context.Context, req *conversation.ClearConversationHistoryReq) error {
|
||||
_, err := crossconversation.DefaultSVC().NewConversationCtx(ctx, &entity.NewConversationCtxRequest{
|
||||
ID: req.ConversationID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (c *ConversationRepository) DeleteMessage(ctx context.Context, req *conversation.DeleteMessageRequest) error {
|
||||
return crossmessage.DefaultSVC().Delete(ctx, &msgentity.DeleteMeta{
|
||||
MessageIDs: []int64{req.MessageID},
|
||||
})
|
||||
}
|
||||
|
||||
func (c *ConversationRepository) EditMessage(ctx context.Context, req *conversation.EditMessageRequest) error {
|
||||
_, err := crossmessage.DefaultSVC().Edit(ctx, &msgentity.Message{
|
||||
ID: req.MessageID,
|
||||
ConversationID: req.ConversationID,
|
||||
Content: req.Content,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConversationRepository) GetLatestRunIDs(ctx context.Context, req *conversation.GetLatestRunIDsRequest) ([]int64, error) {
|
||||
return []int64{0}, nil
|
||||
}
|
||||
|
||||
func (c *ConversationRepository) GetMessagesByRunIDs(ctx context.Context, req *conversation.GetMessagesByRunIDsRequest) (*conversation.GetMessagesByRunIDsResponse, error) {
|
||||
|
||||
messages, err := crossmessage.DefaultSVC().GetByRunIDs(ctx, req.ConversationID, req.RunIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgs, err := convertMessage(messages)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &conversation.GetMessagesByRunIDsResponse{
|
||||
Messages: msgs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func convertMessage(msgs []*msgentity.Message) ([]*conversation.Message, error) {
|
||||
messages := make([]*conversation.Message, 0, len(msgs))
|
||||
for _, m := range msgs {
|
||||
msg := &conversation.Message{
|
||||
ID: m.ID,
|
||||
Role: string(m.Role),
|
||||
ContentType: string(m.ContentType)}
|
||||
|
||||
if m.MultiContent != nil {
|
||||
var mcs []*conversation.Content
|
||||
for _, c := range m.MultiContent {
|
||||
if c.FileData != nil {
|
||||
for _, fd := range c.FileData {
|
||||
mcs = append(mcs, &conversation.Content{
|
||||
Type: string(c.Type),
|
||||
Uri: ptr.Of(fd.Url),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
mcs = append(mcs, &conversation.Content{
|
||||
Type: string(c.Type),
|
||||
Text: ptr.Of(c.Text),
|
||||
})
|
||||
}
|
||||
}
|
||||
msg.MultiContent = mcs
|
||||
} else {
|
||||
msg.Text = ptr.Of(m.Content)
|
||||
}
|
||||
messages = append(messages, msg)
|
||||
}
|
||||
return messages, nil
|
||||
}
|
||||
380
backend/crossdomain/workflow/conversation/conversation_test.go
Normal file
380
backend/crossdomain/workflow/conversation/conversation_test.go
Normal file
@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
apimessage "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/conversation/message/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_convertMessage(t *testing.T) {
|
||||
type args struct {
|
||||
lr *entity.ListResult
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *conversation.MessageListResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "pure text",
|
||||
args: args{
|
||||
lr: &entity.ListResult{
|
||||
Messages: []*entity.Message{
|
||||
{
|
||||
ID: 1,
|
||||
Role: "user",
|
||||
ContentType: "text",
|
||||
MultiContent: []*apimessage.InputMetaData{
|
||||
{
|
||||
Type: "text",
|
||||
Text: "hello",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &conversation.MessageListResponse{
|
||||
Messages: []*conversation.Message{
|
||||
{
|
||||
ID: 1,
|
||||
Role: "user",
|
||||
ContentType: "text",
|
||||
MultiContent: []*conversation.Content{
|
||||
{Type: "text", Text: ptr.Of("hello")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pure file",
|
||||
args: args{
|
||||
lr: &entity.ListResult{
|
||||
Messages: []*entity.Message{
|
||||
{
|
||||
ID: 2,
|
||||
Role: "user",
|
||||
ContentType: "file",
|
||||
MultiContent: []*apimessage.InputMetaData{
|
||||
{
|
||||
Type: "file",
|
||||
FileData: []*apimessage.FileData{
|
||||
{
|
||||
Url: "f_uri_1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "text",
|
||||
Text: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &conversation.MessageListResponse{
|
||||
Messages: []*conversation.Message{
|
||||
{
|
||||
ID: 2,
|
||||
Role: "user",
|
||||
ContentType: "file",
|
||||
MultiContent: []*conversation.Content{
|
||||
{Type: "file", Uri: ptr.Of("f_uri_1")},
|
||||
{Type: "text", Text: ptr.Of("")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "text and file",
|
||||
args: args{
|
||||
lr: &entity.ListResult{
|
||||
Messages: []*entity.Message{
|
||||
{
|
||||
ID: 3,
|
||||
Role: "user",
|
||||
ContentType: "text_file",
|
||||
MultiContent: []*apimessage.InputMetaData{
|
||||
{
|
||||
Type: "text",
|
||||
Text: "hello",
|
||||
},
|
||||
{
|
||||
Type: "file",
|
||||
FileData: []*apimessage.FileData{
|
||||
{
|
||||
Url: "f_uri_2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &conversation.MessageListResponse{
|
||||
Messages: []*conversation.Message{
|
||||
{
|
||||
ID: 3,
|
||||
Role: "user",
|
||||
ContentType: "text_file",
|
||||
MultiContent: []*conversation.Content{
|
||||
{Type: "text", Text: ptr.Of("hello")},
|
||||
{Type: "file", Uri: ptr.Of("f_uri_2")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple files",
|
||||
args: args{
|
||||
lr: &entity.ListResult{
|
||||
Messages: []*entity.Message{
|
||||
{
|
||||
ID: 4,
|
||||
Role: "user",
|
||||
ContentType: "file",
|
||||
MultiContent: []*apimessage.InputMetaData{
|
||||
{
|
||||
Type: "file",
|
||||
FileData: []*apimessage.FileData{
|
||||
{
|
||||
Url: "f_uri_3",
|
||||
},
|
||||
{
|
||||
Url: "f_uri_4",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "text",
|
||||
Text: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &conversation.MessageListResponse{
|
||||
Messages: []*conversation.Message{
|
||||
{
|
||||
ID: 4,
|
||||
Role: "user",
|
||||
ContentType: "file",
|
||||
MultiContent: []*conversation.Content{
|
||||
{Type: "file", Uri: ptr.Of("f_uri_3")},
|
||||
{Type: "file", Uri: ptr.Of("f_uri_4")},
|
||||
{Type: "text", Text: ptr.Of("")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty text",
|
||||
args: args{
|
||||
lr: &entity.ListResult{
|
||||
Messages: []*entity.Message{
|
||||
{
|
||||
ID: 5,
|
||||
Role: "user",
|
||||
ContentType: "text",
|
||||
MultiContent: []*apimessage.InputMetaData{
|
||||
{
|
||||
Type: "text",
|
||||
Text: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &conversation.MessageListResponse{
|
||||
Messages: []*conversation.Message{
|
||||
{
|
||||
ID: 5,
|
||||
Role: "user",
|
||||
ContentType: "text",
|
||||
MultiContent: []*conversation.Content{
|
||||
{Type: "text", Text: ptr.Of("")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pure image",
|
||||
args: args{
|
||||
lr: &entity.ListResult{
|
||||
Messages: []*entity.Message{
|
||||
{
|
||||
ID: 6,
|
||||
Role: "user",
|
||||
ContentType: "image",
|
||||
MultiContent: []*apimessage.InputMetaData{
|
||||
{
|
||||
Type: "image",
|
||||
FileData: []*apimessage.FileData{
|
||||
{
|
||||
Url: "image_uri_5",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "text",
|
||||
Text: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &conversation.MessageListResponse{
|
||||
Messages: []*conversation.Message{
|
||||
{
|
||||
ID: 6,
|
||||
Role: "user",
|
||||
ContentType: "image",
|
||||
MultiContent: []*conversation.Content{
|
||||
{Type: "image", Uri: ptr.Of("image_uri_5")},
|
||||
{Type: "text", Text: ptr.Of("")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple images",
|
||||
args: args{
|
||||
lr: &entity.ListResult{
|
||||
Messages: []*entity.Message{
|
||||
{
|
||||
ID: 7,
|
||||
Role: "user",
|
||||
ContentType: "image",
|
||||
MultiContent: []*apimessage.InputMetaData{
|
||||
{
|
||||
Type: "image",
|
||||
FileData: []*apimessage.FileData{
|
||||
{
|
||||
Url: "file_id_6",
|
||||
},
|
||||
{
|
||||
Url: "file_id_7",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "text",
|
||||
Text: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &conversation.MessageListResponse{
|
||||
Messages: []*conversation.Message{
|
||||
{
|
||||
ID: 7,
|
||||
Role: "user",
|
||||
ContentType: "image",
|
||||
MultiContent: []*conversation.Content{
|
||||
{Type: "image", Uri: ptr.Of("file_id_6")},
|
||||
{Type: "image", Uri: ptr.Of("file_id_7")},
|
||||
{Type: "text", Text: ptr.Of("")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mixed content",
|
||||
args: args{
|
||||
lr: &entity.ListResult{
|
||||
Messages: []*entity.Message{
|
||||
{
|
||||
ID: 8,
|
||||
Role: "user",
|
||||
ContentType: "mix",
|
||||
MultiContent: []*apimessage.InputMetaData{
|
||||
{
|
||||
Type: "text",
|
||||
Text: "hello",
|
||||
},
|
||||
{
|
||||
Type: "image",
|
||||
FileData: []*apimessage.FileData{
|
||||
{
|
||||
Url: "file_id_8",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "file",
|
||||
FileData: []*apimessage.FileData{
|
||||
{
|
||||
Url: "file_id_9",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &conversation.MessageListResponse{
|
||||
Messages: []*conversation.Message{
|
||||
{
|
||||
ID: 8,
|
||||
Role: "user",
|
||||
ContentType: "mix",
|
||||
MultiContent: []*conversation.Content{
|
||||
{Type: "text", Text: ptr.Of("hello")},
|
||||
{Type: "image", Uri: ptr.Of("file_id_8")},
|
||||
{Type: "file", Uri: ptr.Of("file_id_9")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
msgs, err := convertMessage(tt.args.lr.Messages)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("convertMessage() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
for i, msg := range msgs {
|
||||
assert.Equal(t, msg.MultiContent, tt.want.Messages[i].MultiContent)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -127,6 +127,7 @@ func (k *Knowledge) Retrieve(ctx context.Context, r *crossknowledge.RetrieveRequ
|
||||
Query: r.Query,
|
||||
KnowledgeIDs: r.KnowledgeIDs,
|
||||
Strategy: rs,
|
||||
ChatHistory: r.ChatHistory,
|
||||
}
|
||||
|
||||
response, err := k.client.Retrieve(ctx, req)
|
||||
|
||||
@ -29,6 +29,7 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossdatabase"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossknowledge"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossplugin"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossworkflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/app/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/app/repository"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
|
||||
@ -67,6 +68,11 @@ func (a *appServiceImpl) CreateDraftAPP(ctx context.Context, req *CreateDraftAPP
|
||||
return 0, errorx.Wrapf(err, "CreateDraftAPP failed, spaceID=%d", req.SpaceID)
|
||||
}
|
||||
|
||||
err = crossworkflow.DefaultSVC().InitApplicationDefaultConversationTemplate(ctx, req.SpaceID, appID, req.OwnerID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return appID, nil
|
||||
}
|
||||
|
||||
|
||||
@ -58,9 +58,7 @@ func (dao *KnowledgeDocumentSliceDAO) BatchCreate(ctx context.Context, slices []
|
||||
func (dao *KnowledgeDocumentSliceDAO) BatchSetStatus(ctx context.Context, ids []int64, status int32, reason string) error {
|
||||
s := dao.Query.KnowledgeDocumentSlice
|
||||
updates := map[string]any{s.Status.ColumnName().String(): status}
|
||||
if reason != "" {
|
||||
updates[s.FailReason.ColumnName().String()] = reason
|
||||
}
|
||||
updates[s.FailReason.ColumnName().String()] = reason
|
||||
updates[s.UpdatedAt.ColumnName().String()] = time.Now().UnixMilli()
|
||||
_, err := s.WithContext(ctx).Where(s.ID.In(ids...)).Updates(updates)
|
||||
return err
|
||||
|
||||
@ -166,11 +166,22 @@ func (k *knowledgeSVC) indexDocument(ctx context.Context, event *entity.Event) (
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
var errMsg string
|
||||
var statusError errorx.StatusError
|
||||
if errors.As(err, &statusError) && statusError.Code() == errno.ErrKnowledgeNonRetryableCode {
|
||||
if setStatusErr := k.documentRepo.SetStatus(ctx, event.Document.ID, int32(entity.DocumentStatusFailed), err.Error()); setStatusErr != nil {
|
||||
logs.CtxErrorf(ctx, "[indexDocument] set document status failed, err: %v", setStatusErr)
|
||||
var status int32
|
||||
if errors.As(err, &statusError) {
|
||||
errMsg = errorx.ErrorWithoutStack(statusError)
|
||||
if statusError.Code() == errno.ErrKnowledgeNonRetryableCode {
|
||||
status = int32(entity.DocumentStatusFailed)
|
||||
} else {
|
||||
status = int32(entity.DocumentStatusChunking)
|
||||
}
|
||||
} else {
|
||||
errMsg = err.Error()
|
||||
status = int32(entity.DocumentStatusChunking)
|
||||
}
|
||||
if setStatusErr := k.documentRepo.SetStatus(ctx, event.Document.ID, status, errMsg); setStatusErr != nil {
|
||||
logs.CtxErrorf(ctx, "[indexDocument] set document status failed, err: %v", setStatusErr)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@ -545,6 +545,12 @@ func (k *knowledgeSVC) MGetDocumentProgress(ctx context.Context, request *MGetDo
|
||||
if documents[i].Status == int32(entity.DocumentStatusEnable) || documents[i].Status == int32(entity.DocumentStatusFailed) {
|
||||
item.Progress = progressbar.ProcessDone
|
||||
} else {
|
||||
if documents[i].FailReason != "" {
|
||||
item.StatusMsg = documents[i].FailReason
|
||||
item.Status = entity.DocumentStatusFailed
|
||||
progresslist = append(progresslist, &item)
|
||||
continue
|
||||
}
|
||||
err = k.getProgressFromCache(ctx, &item)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "get progress from cache failed, err: %v", err)
|
||||
@ -564,8 +570,9 @@ func (k *knowledgeSVC) getProgressFromCache(ctx context.Context, documentProgres
|
||||
documentProgress.Progress = int(percent)
|
||||
documentProgress.RemainingSec = int64(remainSec)
|
||||
if len(errMsg) != 0 {
|
||||
documentProgress.Progress = 0
|
||||
documentProgress.Status = entity.DocumentStatusChunking
|
||||
documentProgress.Status = entity.DocumentStatusFailed
|
||||
documentProgress.StatusMsg = errMsg
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
@ -1276,6 +1283,16 @@ func (k *knowledgeSVC) fromModelDocument(ctx context.Context, document *model.Kn
|
||||
documentEntity.TableInfo.Columns = append(documentEntity.TableInfo.Columns, document.TableInfo.Columns[i])
|
||||
}
|
||||
}
|
||||
switch document.Status {
|
||||
case int32(entity.DocumentStatusChunking), int32(entity.DocumentStatusInit), int32(entity.DocumentStatusUploading):
|
||||
if document.FailReason != "" {
|
||||
documentEntity.Status = entity.DocumentStatusFailed
|
||||
documentEntity.StatusMsg = document.FailReason
|
||||
}
|
||||
case int32(entity.DocumentStatusFailed):
|
||||
documentEntity.StatusMsg = document.FailReason
|
||||
default:
|
||||
}
|
||||
if len(document.URI) != 0 {
|
||||
objUrl, err := k.storage.GetObjectUrl(ctx, document.URI)
|
||||
if err != nil {
|
||||
|
||||
@ -145,7 +145,7 @@ func (suite *KnowledgeTestSuite) SetupSuite() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
emb, err := hembed.NewEmbedding(embEndpoint)
|
||||
emb, err := hembed.NewEmbedding(embEndpoint, 1024)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ const (
|
||||
func SwitchToDataType(itemType table.FieldItemType) entity.DataType {
|
||||
switch itemType {
|
||||
case table.FieldItemType_Text:
|
||||
return entity.TypeVarchar
|
||||
return entity.TypeText
|
||||
case table.FieldItemType_Number:
|
||||
return entity.TypeBigInt
|
||||
case table.FieldItemType_Date:
|
||||
|
||||
@ -157,7 +157,6 @@ func NewDefaultPluginManifest() *PluginManifest {
|
||||
Value: "Coze/1.0",
|
||||
},
|
||||
},
|
||||
model.ParamInPath: {},
|
||||
model.ParamInQuery: {},
|
||||
},
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ import (
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/conf"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
|
||||
@ -88,7 +89,7 @@ func (p *PluginDraftDAO) getSelected(opt *PluginSelectedOption) (selected []fiel
|
||||
}
|
||||
|
||||
func (p *PluginDraftDAO) Create(ctx context.Context, plugin *entity.PluginInfo) (pluginID int64, err error) {
|
||||
id, err := p.idGen.GenID(ctx)
|
||||
id, err := p.genPluginID(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -117,6 +118,25 @@ func (p *PluginDraftDAO) Create(ctx context.Context, plugin *entity.PluginInfo)
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (p *PluginDraftDAO) genPluginID(ctx context.Context) (id int64, err error) {
|
||||
|
||||
retryTimes := 5
|
||||
for i := 0; i < retryTimes; i++ {
|
||||
id, err = p.idGen.GenID(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, ok := conf.GetPluginProduct(id); !ok {
|
||||
break
|
||||
}
|
||||
if i == retryTimes-1 {
|
||||
return 0, fmt.Errorf("id %d is confilict with product plugin id.", id)
|
||||
}
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (p *PluginDraftDAO) Get(ctx context.Context, pluginID int64, opt *PluginSelectedOption) (plugin *entity.PluginInfo, exist bool, err error) {
|
||||
table := p.query.PluginDraft
|
||||
pl, err := table.WithContext(ctx).
|
||||
@ -262,7 +282,7 @@ func (p *PluginDraftDAO) Update(ctx context.Context, plugin *entity.PluginInfo)
|
||||
}
|
||||
|
||||
func (p *PluginDraftDAO) CreateWithTX(ctx context.Context, tx *query.QueryTx, plugin *entity.PluginInfo) (pluginID int64, err error) {
|
||||
id, err := p.idGen.GenID(ctx)
|
||||
id, err := p.genPluginID(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ import (
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/conf"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
|
||||
@ -90,7 +91,8 @@ func (t *ToolDraftDAO) getSelected(opt *ToolSelectedOption) (selected []field.Ex
|
||||
}
|
||||
|
||||
func (t *ToolDraftDAO) Create(ctx context.Context, tool *entity.ToolInfo) (toolID int64, err error) {
|
||||
id, err := t.idGen.GenID(ctx)
|
||||
|
||||
id, err := t.genToolID(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -111,6 +113,27 @@ func (t *ToolDraftDAO) Create(ctx context.Context, tool *entity.ToolInfo) (toolI
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (t *ToolDraftDAO) genToolID(ctx context.Context) (id int64, err error) {
|
||||
|
||||
retryTimes := 5
|
||||
|
||||
for i := 0; i < retryTimes; i++ {
|
||||
id, err = t.idGen.GenID(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if _, ok := conf.GetToolProduct(id); !ok {
|
||||
break
|
||||
}
|
||||
if i == retryTimes-1 {
|
||||
return 0, fmt.Errorf("id %d is confilict with product tool id.", id)
|
||||
}
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (t *ToolDraftDAO) Get(ctx context.Context, toolID int64) (tool *entity.ToolInfo, exist bool, err error) {
|
||||
table := t.query.ToolDraft
|
||||
tl, err := table.WithContext(ctx).
|
||||
@ -335,7 +358,7 @@ func (t *ToolDraftDAO) BatchCreateWithTX(ctx context.Context, tx *query.QueryTx,
|
||||
tls := make([]*model.ToolDraft, 0, len(tools))
|
||||
|
||||
for _, tool := range tools {
|
||||
id, err := t.idGen.GenID(ctx)
|
||||
id, err := t.genToolID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ import (
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/tidwall/sjson"
|
||||
|
||||
einoCompose "github.com/cloudwego/eino/compose"
|
||||
|
||||
@ -479,11 +480,6 @@ func (t *toolExecutor) execute(ctx context.Context, argumentsInJson string) (res
|
||||
return nil, err
|
||||
}
|
||||
|
||||
requestStr, err := sonic.MarshalString(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq, err := t.buildHTTPRequest(ctx, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -504,18 +500,29 @@ func (t *toolExecutor) execute(ctx context.Context, argumentsInJson string) (res
|
||||
}
|
||||
|
||||
var reqBodyBytes []byte
|
||||
if httpReq.Body != nil {
|
||||
reqBodyBytes, err = io.ReadAll(httpReq.Body)
|
||||
if httpReq.GetBody != nil {
|
||||
reqBody, err := httpReq.GetBody()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer reqBody.Close()
|
||||
|
||||
reqBodyBytes, err = io.ReadAll(reqBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
requestStr, err := genRequestString(httpReq, reqBodyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
restyReq := t.svc.httpCli.NewRequest()
|
||||
restyReq.Header = httpReq.Header
|
||||
restyReq.Method = httpReq.Method
|
||||
restyReq.URL = httpReq.URL.String()
|
||||
if len(reqBodyBytes) > 0 {
|
||||
if reqBodyBytes != nil {
|
||||
restyReq.SetBody(reqBodyBytes)
|
||||
}
|
||||
restyReq.SetContext(ctx)
|
||||
@ -559,6 +566,46 @@ func (t *toolExecutor) execute(ctx context.Context, argumentsInJson string) (res
|
||||
}, nil
|
||||
}
|
||||
|
||||
func genRequestString(req *http.Request, body []byte) (string, error) {
|
||||
type Request struct {
|
||||
Path string `json:"path"`
|
||||
Header map[string]string `json:"header"`
|
||||
Query map[string]string `json:"query"`
|
||||
Body *[]byte `json:"body"`
|
||||
}
|
||||
|
||||
req_ := &Request{
|
||||
Path: req.URL.Path,
|
||||
Header: map[string]string{},
|
||||
Query: map[string]string{},
|
||||
}
|
||||
|
||||
if len(req.Header) > 0 {
|
||||
for k, v := range req.Header {
|
||||
req_.Header[k] = v[0]
|
||||
}
|
||||
}
|
||||
if len(req.URL.Query()) > 0 {
|
||||
for k, v := range req.URL.Query() {
|
||||
req_.Query[k] = v[0]
|
||||
}
|
||||
}
|
||||
|
||||
requestStr, err := sonic.MarshalString(req_)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[genRequestString] marshal failed, err=%s", err)
|
||||
}
|
||||
|
||||
if body != nil {
|
||||
requestStr, err = sjson.SetRaw(requestStr, "body", string(body))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[genRequestString] set body failed, err=%s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return requestStr, nil
|
||||
}
|
||||
|
||||
func (t *toolExecutor) preprocessArgumentsInJson(ctx context.Context, argumentsInJson string) (args map[string]any, err error) {
|
||||
args, err = t.prepareArguments(ctx, argumentsInJson)
|
||||
if err != nil {
|
||||
@ -653,23 +700,13 @@ func (t *toolExecutor) buildHTTPRequest(ctx context.Context, argMaps map[string]
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reqURL, err := locArgs.buildHTTPRequestURL(ctx, rawURL)
|
||||
commonParams := t.plugin.Manifest.CommonParams
|
||||
|
||||
reqURL, err := locArgs.buildHTTPRequestURL(ctx, rawURL, commonParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq, err = http.NewRequestWithContext(ctx, tool.GetMethod(), reqURL.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
header, err := locArgs.buildHTTPRequestHeader(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq.Header = header
|
||||
|
||||
bodyArgs := map[string]any{}
|
||||
for k, v := range argMaps {
|
||||
if _, ok := locArgs.header[k]; ok {
|
||||
@ -684,13 +721,27 @@ func (t *toolExecutor) buildHTTPRequest(ctx context.Context, argMaps map[string]
|
||||
bodyArgs[k] = v
|
||||
}
|
||||
|
||||
bodyBytes, contentType, err := t.buildRequestBody(ctx, tool.Operation, bodyArgs)
|
||||
commonBody := commonParams[model.ParamInBody]
|
||||
bodyBytes, contentType, err := t.buildRequestBody(ctx, tool.Operation, bodyArgs, commonBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq, err = http.NewRequestWithContext(ctx, tool.GetMethod(), reqURL.String(), bytes.NewBuffer(bodyBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commonHeader := commonParams[model.ParamInHeader]
|
||||
header, err := locArgs.buildHTTPRequestHeader(ctx, commonHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq.Header = header
|
||||
|
||||
if len(bodyBytes) > 0 {
|
||||
httpReq.Header.Set("Content-Type", contentType)
|
||||
httpReq.Body = io.NopCloser(bytes.NewReader(bodyBytes))
|
||||
}
|
||||
|
||||
return httpReq, nil
|
||||
@ -698,13 +749,6 @@ func (t *toolExecutor) buildHTTPRequest(ctx context.Context, argMaps map[string]
|
||||
|
||||
func (t *toolExecutor) prepareArguments(_ context.Context, argumentsInJson string) (map[string]any, error) {
|
||||
args := map[string]any{}
|
||||
for loc, params := range t.plugin.Manifest.CommonParams {
|
||||
for _, p := range params {
|
||||
if loc != model.ParamInBody {
|
||||
args[p.Name] = p.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
decoder := sonic.ConfigDefault.NewDecoder(bytes.NewBufferString(argumentsInJson))
|
||||
decoder.UseNumber()
|
||||
@ -1175,7 +1219,9 @@ type valueWithSchema struct {
|
||||
paramSchema *openapi3.Parameter
|
||||
}
|
||||
|
||||
func (l *locationArguments) buildHTTPRequestURL(_ context.Context, rawURL string) (reqURL *url.URL, err error) {
|
||||
func (l *locationArguments) buildHTTPRequestURL(_ context.Context, rawURL string,
|
||||
commonParams map[model.HTTPParamLocation][]*common.CommonParamSchema) (reqURL *url.URL, err error) {
|
||||
|
||||
if len(l.path) > 0 {
|
||||
for k, v := range l.path {
|
||||
vStr, err := encoder.EncodeParameter(v.paramSchema, v.argValue)
|
||||
@ -1186,9 +1232,8 @@ func (l *locationArguments) buildHTTPRequestURL(_ context.Context, rawURL string
|
||||
}
|
||||
}
|
||||
|
||||
encodeQuery := ""
|
||||
query := url.Values{}
|
||||
if len(l.query) > 0 {
|
||||
query := url.Values{}
|
||||
for k, val := range l.query {
|
||||
switch v := val.argValue.(type) {
|
||||
case []any:
|
||||
@ -1199,10 +1244,18 @@ func (l *locationArguments) buildHTTPRequestURL(_ context.Context, rawURL string
|
||||
query.Add(k, encoder.MustString(v))
|
||||
}
|
||||
}
|
||||
|
||||
encodeQuery = query.Encode()
|
||||
}
|
||||
|
||||
commonQuery := commonParams[model.ParamInQuery]
|
||||
for _, v := range commonQuery {
|
||||
if _, ok := l.query[v.Name]; ok {
|
||||
continue
|
||||
}
|
||||
query.Add(v.Name, v.Value)
|
||||
}
|
||||
|
||||
encodeQuery := query.Encode()
|
||||
|
||||
reqURL, err = url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1217,7 +1270,7 @@ func (l *locationArguments) buildHTTPRequestURL(_ context.Context, rawURL string
|
||||
return reqURL, nil
|
||||
}
|
||||
|
||||
func (l *locationArguments) buildHTTPRequestHeader(_ context.Context) (http.Header, error) {
|
||||
func (l *locationArguments) buildHTTPRequestHeader(_ context.Context, commonHeaders []*common.CommonParamSchema) (http.Header, error) {
|
||||
header := http.Header{}
|
||||
if len(l.header) > 0 {
|
||||
for k, v := range l.header {
|
||||
@ -1232,44 +1285,64 @@ func (l *locationArguments) buildHTTPRequestHeader(_ context.Context) (http.Head
|
||||
}
|
||||
}
|
||||
|
||||
for _, h := range commonHeaders {
|
||||
if header.Get(h.Name) != "" {
|
||||
continue
|
||||
}
|
||||
header.Add(h.Name, h.Value)
|
||||
}
|
||||
|
||||
return header, nil
|
||||
}
|
||||
|
||||
func (t *toolExecutor) buildRequestBody(ctx context.Context, op *model.Openapi3Operation, bodyArgs map[string]any) (body []byte, contentType string, err error) {
|
||||
func (t *toolExecutor) buildRequestBody(ctx context.Context, op *model.Openapi3Operation, bodyArgs map[string]any,
|
||||
commonBody []*common.CommonParamSchema) (body []byte, contentType string, err error) {
|
||||
|
||||
var bodyMap map[string]any
|
||||
|
||||
contentType, bodySchema := t.getReqBodySchema(op)
|
||||
if bodySchema == nil || bodySchema.Value == nil {
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
if len(bodySchema.Value.Properties) == 0 {
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
bodyMap, err := t.injectRequestBodyDefaultValue(ctx, bodySchema.Value, bodyArgs)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
for paramName, prop := range bodySchema.Value.Properties {
|
||||
value, ok := bodyMap[paramName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
_value, err := encoder.TryFixValueType(paramName, prop, value)
|
||||
if bodySchema != nil && len(bodySchema.Value.Properties) > 0 {
|
||||
bodyMap, err = t.injectRequestBodyDefaultValue(ctx, bodySchema.Value, bodyArgs)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
bodyMap[paramName] = _value
|
||||
for paramName, prop := range bodySchema.Value.Properties {
|
||||
value, ok := bodyMap[paramName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
_value, err := encoder.TryFixValueType(paramName, prop, value)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
bodyMap[paramName] = _value
|
||||
}
|
||||
|
||||
body, err = encoder.EncodeBodyWithContentType(contentType, bodyMap)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("[buildRequestBody] EncodeBodyWithContentType failed, err=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
reqBodyStr, err := encoder.EncodeBodyWithContentType(contentType, bodyMap)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("[buildRequestBody] EncodeBodyWithContentType failed, err=%v", err)
|
||||
commonBody_ := make([]*common.CommonParamSchema, 0, len(commonBody))
|
||||
for _, v := range commonBody {
|
||||
if _, ok := bodyMap[v.Name]; ok {
|
||||
continue
|
||||
}
|
||||
commonBody_ = append(commonBody_, v)
|
||||
}
|
||||
|
||||
return reqBodyStr, contentType, nil
|
||||
for _, v := range commonBody_ {
|
||||
body, err = sjson.SetRawBytes(body, v.Name, []byte(v.Value))
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("[buildRequestBody] SetRawBytes failed, err=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return body, contentType, nil
|
||||
}
|
||||
|
||||
func (t *toolExecutor) injectRequestBodyDefaultValue(ctx context.Context, sc *openapi3.Schema, vals map[string]any) (newVals map[string]any, err error) {
|
||||
@ -1327,7 +1400,7 @@ func (t *toolExecutor) injectRequestBodyDefaultValue(ctx context.Context, sc *op
|
||||
}
|
||||
|
||||
func (t *toolExecutor) getReqBodySchema(op *model.Openapi3Operation) (string, *openapi3.SchemaRef) {
|
||||
if op.RequestBody == nil || op.RequestBody.Value == nil || len(op.RequestBody.Value.Content) == 0 {
|
||||
if op.RequestBody == nil || len(op.RequestBody.Value.Content) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
|
||||
49
backend/domain/plugin/service/exec_tool_test.go
Normal file
49
backend/domain/plugin/service/exec_tool_test.go
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
. "github.com/bytedance/mockey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGenRequestString(t *testing.T) {
|
||||
PatchConvey("", t, func() {
|
||||
requestStr, err := genRequestString(&http.Request{
|
||||
Header: http.Header{
|
||||
"Content-Type": []string{"application/json"},
|
||||
},
|
||||
Method: http.MethodPost,
|
||||
URL: &url.URL{Path: "/test"},
|
||||
}, []byte(`{"a": 1}`))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `{"header":{"Content-Type":["application/json"]},"query":null,"path":"/test","body":{"a": 1}}`, requestStr)
|
||||
})
|
||||
|
||||
PatchConvey("", t, func() {
|
||||
var body []byte
|
||||
requestStr, err := genRequestString(&http.Request{
|
||||
URL: &url.URL{Path: "/test"},
|
||||
}, body)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `{"header":null,"query":null,"path":"/test","body":null}`, requestStr)
|
||||
})
|
||||
}
|
||||
@ -46,6 +46,7 @@ import (
|
||||
|
||||
func (p *pluginServiceImpl) CreateDraftPlugin(ctx context.Context, req *CreateDraftPluginRequest) (pluginID int64, err error) {
|
||||
mf := entity.NewDefaultPluginManifest()
|
||||
mf.CommonParams = map[model.HTTPParamLocation][]*plugin_develop_common.CommonParamSchema{}
|
||||
mf.NameForHuman = req.Name
|
||||
mf.NameForModel = req.Name
|
||||
mf.DescriptionForHuman = req.Desc
|
||||
@ -65,11 +66,11 @@ func (p *pluginServiceImpl) CreateDraftPlugin(ctx context.Context, req *CreateDr
|
||||
return 0, fmt.Errorf("invalid location '%s'", loc.String())
|
||||
}
|
||||
for _, param := range params {
|
||||
mParams := mf.CommonParams[location]
|
||||
mParams = append(mParams, &plugin_develop_common.CommonParamSchema{
|
||||
Name: param.Name,
|
||||
Value: param.Value,
|
||||
})
|
||||
mf.CommonParams[location] = append(mf.CommonParams[location],
|
||||
&plugin_develop_common.CommonParamSchema{
|
||||
Name: param.Name,
|
||||
Value: param.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -194,7 +194,7 @@ func (p *pluginServiceImpl) getAccessTokenByAuthorizationCode(ctx context.Contex
|
||||
meta := ci.Meta
|
||||
info, exist, err := p.oauthRepo.GetAuthorizationCode(ctx, ci.Meta)
|
||||
if err != nil {
|
||||
return "", errorx.Wrapf(err, "GetAuthorizationCode failed, userID=%s, pluginID=%d, isDraft=%p",
|
||||
return "", errorx.Wrapf(err, "GetAuthorizationCode failed, userID=%s, pluginID=%d, isDraft=%t",
|
||||
meta.UserID, meta.PluginID, meta.IsDraft)
|
||||
}
|
||||
if !exist {
|
||||
|
||||
@ -53,6 +53,20 @@ type AsTool interface {
|
||||
allInterruptEvents map[string]*entity.ToolInterruptEvent) compose.Option
|
||||
}
|
||||
|
||||
type ConversationService interface {
|
||||
CreateDraftConversationTemplate(ctx context.Context, template *vo.CreateConversationTemplateMeta) (int64, error)
|
||||
UpdateDraftConversationTemplateName(ctx context.Context, appID int64, userID int64, templateID int64, name string) error
|
||||
DeleteDraftConversationTemplate(ctx context.Context, templateID int64, wfID2ConversationName map[int64]string) (int64, error)
|
||||
|
||||
CheckWorkflowsToReplace(ctx context.Context, appID int64, templateID int64) ([]*entity.Workflow, error)
|
||||
DeleteDynamicConversation(ctx context.Context, env vo.Env, templateID int64) (int64, error)
|
||||
ListConversationTemplate(ctx context.Context, env vo.Env, policy *vo.ListConversationTemplatePolicy) ([]*entity.ConversationTemplate, error)
|
||||
MGetStaticConversation(ctx context.Context, env vo.Env, userID, connectorID int64, templateIDs []int64) ([]*entity.StaticConversation, error)
|
||||
ListDynamicConversation(ctx context.Context, env vo.Env, policy *vo.ListConversationPolicy) ([]*entity.DynamicConversation, error)
|
||||
ReleaseConversationTemplate(ctx context.Context, appID int64, version string) error
|
||||
InitApplicationDefaultConversationTemplate(ctx context.Context, spaceID int64, appID int64, userID int64) error
|
||||
}
|
||||
|
||||
type InterruptEventStore interface {
|
||||
SaveInterruptEvents(ctx context.Context, wfExeID int64, events []*entity.InterruptEvent) error
|
||||
GetFirstInterruptEvent(ctx context.Context, wfExeID int64) (*entity.InterruptEvent, bool, error)
|
||||
@ -90,3 +104,22 @@ type ToolFromWorkflow interface {
|
||||
TerminatePlan() vo.TerminatePlan
|
||||
GetWorkflow() *entity.Workflow
|
||||
}
|
||||
|
||||
type ConversationIDGenerator func(ctx context.Context, appID int64, userID, connectorID int64) (int64, error)
|
||||
|
||||
type ConversationRepository interface {
|
||||
CreateDraftConversationTemplate(ctx context.Context, template *vo.CreateConversationTemplateMeta) (int64, error)
|
||||
UpdateDraftConversationTemplateName(ctx context.Context, templateID int64, name string) error
|
||||
DeleteDraftConversationTemplate(ctx context.Context, templateID int64) (int64, error)
|
||||
GetConversationTemplate(ctx context.Context, env vo.Env, policy vo.GetConversationTemplatePolicy) (*entity.ConversationTemplate, bool, error)
|
||||
DeleteDynamicConversation(ctx context.Context, env vo.Env, id int64) (int64, error)
|
||||
ListConversationTemplate(ctx context.Context, env vo.Env, policy *vo.ListConversationTemplatePolicy) ([]*entity.ConversationTemplate, error)
|
||||
MGetStaticConversation(ctx context.Context, env vo.Env, userID, connectorID int64, templateIDs []int64) ([]*entity.StaticConversation, error)
|
||||
GetOrCreateStaticConversation(ctx context.Context, env vo.Env, idGen ConversationIDGenerator, meta *vo.CreateStaticConversation) (int64, bool, error)
|
||||
GetOrCreateDynamicConversation(ctx context.Context, env vo.Env, idGen ConversationIDGenerator, meta *vo.CreateDynamicConversation) (int64, bool, error)
|
||||
GetDynamicConversationByName(ctx context.Context, env vo.Env, appID, connectorID, userID int64, name string) (*entity.DynamicConversation, bool, error)
|
||||
GetStaticConversationByTemplateID(ctx context.Context, env vo.Env, userID, connectorID, templateID int64) (*entity.StaticConversation, bool, error)
|
||||
ListDynamicConversation(ctx context.Context, env vo.Env, policy *vo.ListConversationPolicy) ([]*entity.DynamicConversation, error)
|
||||
BatchCreateOnlineConversationTemplate(ctx context.Context, templates []*entity.ConversationTemplate, version string) error
|
||||
UpdateDynamicConversationNameByID(ctx context.Context, env vo.Env, templateID int64, name string) error
|
||||
}
|
||||
|
||||
@ -16,46 +16,116 @@
|
||||
|
||||
package conversation
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type ClearMessageRequest struct {
|
||||
Name string
|
||||
}
|
||||
type ClearMessageResponse struct {
|
||||
IsSuccess bool
|
||||
}
|
||||
type CreateConversationRequest struct {
|
||||
Name string
|
||||
AppID int64
|
||||
UserID int64
|
||||
ConnectorID int64
|
||||
}
|
||||
|
||||
type CreateConversationResponse struct {
|
||||
Result map[string]any
|
||||
type CreateMessageRequest struct {
|
||||
ConversationID int64
|
||||
Role string
|
||||
Content string
|
||||
ContentType string
|
||||
UserID int64
|
||||
AppID int64
|
||||
RunID int64
|
||||
}
|
||||
|
||||
type ListMessageRequest struct {
|
||||
ConversationName string
|
||||
Limit *int
|
||||
BeforeID *string
|
||||
AfterID *string
|
||||
}
|
||||
type Message struct {
|
||||
ID string `json:"id"`
|
||||
Role string `json:"role"`
|
||||
ContentType string `json:"contentType"`
|
||||
Content string `json:"content"`
|
||||
type MessageListRequest struct {
|
||||
ConversationID int64
|
||||
Limit int64
|
||||
BeforeID *string
|
||||
AfterID *string
|
||||
UserID int64
|
||||
AppID int64
|
||||
OrderBy *string
|
||||
}
|
||||
|
||||
type ListMessageResponse struct {
|
||||
type MessageListResponse struct {
|
||||
Messages []*Message
|
||||
FirstID string
|
||||
LastID string
|
||||
HasMore bool
|
||||
}
|
||||
|
||||
var ConversationManagerImpl ConversationManager
|
||||
var conversationManagerImpl ConversationManager
|
||||
|
||||
type ConversationManager interface {
|
||||
ClearMessage(context.Context, *ClearMessageRequest) (*ClearMessageResponse, error)
|
||||
CreateConversation(ctx context.Context, c *CreateConversationRequest) (*CreateConversationResponse, error)
|
||||
MessageList(ctx context.Context, req *ListMessageRequest) (*ListMessageResponse, error)
|
||||
func GetConversationManager() ConversationManager {
|
||||
return conversationManagerImpl
|
||||
}
|
||||
|
||||
func SetConversationManager(c ConversationManager) {
|
||||
conversationManagerImpl = c
|
||||
}
|
||||
|
||||
type ConversationHistoryRequest struct {
|
||||
ConversationID int64
|
||||
AppID int64
|
||||
UserID int64
|
||||
Rounds int64
|
||||
}
|
||||
|
||||
type Content struct {
|
||||
Type string `json:"type"`
|
||||
Text *string `json:"text,omitempty"`
|
||||
Uri *string `json:"uri,omitempty"`
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
ID int64
|
||||
Role string `json:"role"` // user or assistant
|
||||
MultiContent []*Content `json:"multi_content"`
|
||||
Text *string `json:"text,omitempty"`
|
||||
ContentType string `json:"content_type"`
|
||||
}
|
||||
|
||||
type ConversationHistoryResponse struct {
|
||||
Messages []*Message
|
||||
}
|
||||
|
||||
type GetLatestRunIDsRequest struct {
|
||||
ConversationID int64
|
||||
UserID int64
|
||||
AppID int64
|
||||
Rounds int64
|
||||
}
|
||||
type ClearConversationHistoryReq struct {
|
||||
ConversationID int64
|
||||
}
|
||||
|
||||
type DeleteMessageRequest struct {
|
||||
ConversationID int64
|
||||
MessageID int64
|
||||
}
|
||||
|
||||
type EditMessageRequest struct {
|
||||
ConversationID int64
|
||||
MessageID int64
|
||||
Content string
|
||||
}
|
||||
|
||||
type GetMessagesByRunIDsRequest struct {
|
||||
ConversationID int64
|
||||
RunIDs []int64
|
||||
}
|
||||
|
||||
type GetMessagesByRunIDsResponse struct {
|
||||
Messages []*Message
|
||||
}
|
||||
|
||||
//go:generate mockgen -destination conversationmock/conversation_mock.go --package conversationmock -source conversation.go
|
||||
type ConversationManager interface {
|
||||
CreateConversation(ctx context.Context, req *CreateConversationRequest) (int64, error)
|
||||
CreateMessage(ctx context.Context, req *CreateMessageRequest) (int64, error)
|
||||
MessageList(ctx context.Context, req *MessageListRequest) (*MessageListResponse, error)
|
||||
GetLatestRunIDs(ctx context.Context, req *GetLatestRunIDsRequest) ([]int64, error)
|
||||
GetMessagesByRunIDs(ctx context.Context, req *GetMessagesByRunIDsRequest) (*GetMessagesByRunIDsResponse, error)
|
||||
ClearConversationHistory(ctx context.Context, req *ClearConversationHistoryReq) error
|
||||
DeleteMessage(ctx context.Context, req *DeleteMessageRequest) error
|
||||
EditMessage(ctx context.Context, req *EditMessageRequest) error
|
||||
}
|
||||
|
||||
@ -0,0 +1,159 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: conversation.go
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -destination conversationmock/conversation_mock.go --package conversationmock -source conversation.go
|
||||
//
|
||||
|
||||
// Package conversationmock is a generated GoMock package.
|
||||
package conversationmock
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
conversation "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockConversationManager is a mock of ConversationManager interface.
|
||||
type MockConversationManager struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockConversationManagerMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockConversationManagerMockRecorder is the mock recorder for MockConversationManager.
|
||||
type MockConversationManagerMockRecorder struct {
|
||||
mock *MockConversationManager
|
||||
}
|
||||
|
||||
// NewMockConversationManager creates a new mock instance.
|
||||
func NewMockConversationManager(ctrl *gomock.Controller) *MockConversationManager {
|
||||
mock := &MockConversationManager{ctrl: ctrl}
|
||||
mock.recorder = &MockConversationManagerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockConversationManager) EXPECT() *MockConversationManagerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// ClearConversationHistory mocks base method.
|
||||
func (m *MockConversationManager) ClearConversationHistory(ctx context.Context, req *conversation.ClearConversationHistoryReq) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ClearConversationHistory", ctx, req)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ClearConversationHistory indicates an expected call of ClearConversationHistory.
|
||||
func (mr *MockConversationManagerMockRecorder) ClearConversationHistory(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClearConversationHistory", reflect.TypeOf((*MockConversationManager)(nil).ClearConversationHistory), ctx, req)
|
||||
}
|
||||
|
||||
// CreateConversation mocks base method.
|
||||
func (m *MockConversationManager) CreateConversation(ctx context.Context, req *conversation.CreateConversationRequest) (int64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateConversation", ctx, req)
|
||||
ret0, _ := ret[0].(int64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateConversation indicates an expected call of CreateConversation.
|
||||
func (mr *MockConversationManagerMockRecorder) CreateConversation(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateConversation", reflect.TypeOf((*MockConversationManager)(nil).CreateConversation), ctx, req)
|
||||
}
|
||||
|
||||
// CreateMessage mocks base method.
|
||||
func (m *MockConversationManager) CreateMessage(ctx context.Context, req *conversation.CreateMessageRequest) (int64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateMessage", ctx, req)
|
||||
ret0, _ := ret[0].(int64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateMessage indicates an expected call of CreateMessage.
|
||||
func (mr *MockConversationManagerMockRecorder) CreateMessage(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateMessage", reflect.TypeOf((*MockConversationManager)(nil).CreateMessage), ctx, req)
|
||||
}
|
||||
|
||||
// DeleteMessage mocks base method.
|
||||
func (m *MockConversationManager) DeleteMessage(ctx context.Context, req *conversation.DeleteMessageRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteMessage", ctx, req)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteMessage indicates an expected call of DeleteMessage.
|
||||
func (mr *MockConversationManagerMockRecorder) DeleteMessage(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteMessage", reflect.TypeOf((*MockConversationManager)(nil).DeleteMessage), ctx, req)
|
||||
}
|
||||
|
||||
// EditMessage mocks base method.
|
||||
func (m *MockConversationManager) EditMessage(ctx context.Context, req *conversation.EditMessageRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EditMessage", ctx, req)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// EditMessage indicates an expected call of EditMessage.
|
||||
func (mr *MockConversationManagerMockRecorder) EditMessage(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EditMessage", reflect.TypeOf((*MockConversationManager)(nil).EditMessage), ctx, req)
|
||||
}
|
||||
|
||||
// GetLatestRunIDs mocks base method.
|
||||
func (m *MockConversationManager) GetLatestRunIDs(ctx context.Context, req *conversation.GetLatestRunIDsRequest) ([]int64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetLatestRunIDs", ctx, req)
|
||||
ret0, _ := ret[0].([]int64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetLatestRunIDs indicates an expected call of GetLatestRunIDs.
|
||||
func (mr *MockConversationManagerMockRecorder) GetLatestRunIDs(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestRunIDs", reflect.TypeOf((*MockConversationManager)(nil).GetLatestRunIDs), ctx, req)
|
||||
}
|
||||
|
||||
// GetMessagesByRunIDs mocks base method.
|
||||
func (m *MockConversationManager) GetMessagesByRunIDs(ctx context.Context, req *conversation.GetMessagesByRunIDsRequest) (*conversation.GetMessagesByRunIDsResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetMessagesByRunIDs", ctx, req)
|
||||
ret0, _ := ret[0].(*conversation.GetMessagesByRunIDsResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetMessagesByRunIDs indicates an expected call of GetMessagesByRunIDs.
|
||||
func (mr *MockConversationManagerMockRecorder) GetMessagesByRunIDs(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMessagesByRunIDs", reflect.TypeOf((*MockConversationManager)(nil).GetMessagesByRunIDs), ctx, req)
|
||||
}
|
||||
|
||||
// MessageList mocks base method.
|
||||
func (m *MockConversationManager) MessageList(ctx context.Context, req *conversation.MessageListRequest) (*conversation.MessageListResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "MessageList", ctx, req)
|
||||
ret0, _ := ret[0].(*conversation.MessageListResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// MessageList indicates an expected call of MessageList.
|
||||
func (mr *MockConversationManagerMockRecorder) MessageList(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MessageList", reflect.TypeOf((*MockConversationManager)(nil).MessageList), ctx, req)
|
||||
}
|
||||
@ -19,6 +19,7 @@ package knowledge
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/document/parser"
|
||||
)
|
||||
|
||||
@ -87,6 +88,7 @@ type RetrieveRequest struct {
|
||||
Query string
|
||||
KnowledgeIDs []int64
|
||||
RetrievalStrategy *RetrievalStrategy
|
||||
ChatHistory []*schema.Message
|
||||
}
|
||||
|
||||
type Slice struct {
|
||||
|
||||
@ -35,6 +35,7 @@ type LLMParams struct {
|
||||
TopP *float64 `json:"topP"`
|
||||
TopK *int `json:"topK"`
|
||||
EnableChatHistory bool `json:"enableChatHistory"`
|
||||
ChatHistoryRound int64 `json:"chatHistoryRound"`
|
||||
SystemPrompt string `json:"systemPrompt"`
|
||||
ResponseFormat ResponseFormat `json:"responseFormat"`
|
||||
}
|
||||
|
||||
37
backend/domain/workflow/entity/chatflow_role.go
Normal file
37
backend/domain/workflow/entity/chatflow_role.go
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package entity
|
||||
|
||||
import "time"
|
||||
|
||||
type ChatFlowRole struct {
|
||||
ID int64
|
||||
WorkflowID int64
|
||||
ConnectorID int64
|
||||
Name string
|
||||
Description string
|
||||
Version string
|
||||
AvatarUri string
|
||||
BackgroundImageInfo string
|
||||
OnboardingInfo string
|
||||
SuggestReplyInfo string
|
||||
AudioConfig string
|
||||
UserInputConfig string
|
||||
CreatorID int64
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
39
backend/domain/workflow/entity/conversation.go
Normal file
39
backend/domain/workflow/entity/conversation.go
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package entity
|
||||
|
||||
type ConversationTemplate struct {
|
||||
SpaceID int64
|
||||
AppID int64
|
||||
Name string
|
||||
TemplateID int64
|
||||
}
|
||||
|
||||
type StaticConversation struct {
|
||||
UserID int64
|
||||
ConnectorID int64
|
||||
TemplateID int64
|
||||
ConversationID int64
|
||||
}
|
||||
|
||||
type DynamicConversation struct {
|
||||
ID int64
|
||||
UserID int64
|
||||
ConnectorID int64
|
||||
ConversationID int64
|
||||
Name string
|
||||
}
|
||||
@ -16,6 +16,15 @@
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type NodeType string
|
||||
|
||||
type NodeTypeMeta struct {
|
||||
@ -116,8 +125,11 @@ const (
|
||||
NodeTypeCodeRunner NodeType = "CodeRunner"
|
||||
NodeTypePlugin NodeType = "Plugin"
|
||||
NodeTypeCreateConversation NodeType = "CreateConversation"
|
||||
NodeTypeConversationList NodeType = "ConversationList"
|
||||
NodeTypeMessageList NodeType = "MessageList"
|
||||
NodeTypeClearMessage NodeType = "ClearMessage"
|
||||
NodeTypeCreateMessage NodeType = "CreateMessage"
|
||||
NodeTypeEditMessage NodeType = "EditMessage"
|
||||
NodeTypeDeleteMessage NodeType = "DeleteMessage"
|
||||
NodeTypeLambda NodeType = "Lambda"
|
||||
NodeTypeLLM NodeType = "LLM"
|
||||
NodeTypeSelector NodeType = "Selector"
|
||||
@ -125,9 +137,93 @@ const (
|
||||
NodeTypeSubWorkflow NodeType = "SubWorkflow"
|
||||
NodeTypeJsonSerialization NodeType = "JsonSerialization"
|
||||
NodeTypeJsonDeserialization NodeType = "JsonDeserialization"
|
||||
NodeTypeConversationUpdate NodeType = "ConversationUpdate"
|
||||
NodeTypeConversationDelete NodeType = "ConversationDelete"
|
||||
NodeTypeClearConversationHistory NodeType = "ClearConversationHistory"
|
||||
NodeTypeConversationHistory NodeType = "ConversationHistory"
|
||||
NodeTypeComment NodeType = "Comment"
|
||||
)
|
||||
|
||||
const (
|
||||
EntryNodeKey = "100001"
|
||||
ExitNodeKey = "900001"
|
||||
)
|
||||
|
||||
var blockType2NodeType = map[vo.BlockType]NodeType{
|
||||
vo.BlockTypeBotStart: NodeTypeEntry,
|
||||
vo.BlockTypeBotEnd: NodeTypeExit,
|
||||
vo.BlockTypeBotLLM: NodeTypeLLM,
|
||||
vo.BlockTypeBotAPI: NodeTypePlugin,
|
||||
vo.BlockTypeBotCode: NodeTypeCodeRunner,
|
||||
vo.BlockTypeBotDataset: NodeTypeKnowledgeRetriever,
|
||||
vo.BlockTypeCondition: NodeTypeSelector,
|
||||
vo.BlockTypeBotSubWorkflow: NodeTypeSubWorkflow,
|
||||
vo.BlockTypeDatabase: NodeTypeDatabaseCustomSQL,
|
||||
vo.BlockTypeBotMessage: NodeTypeOutputEmitter,
|
||||
vo.BlockTypeBotText: NodeTypeTextProcessor,
|
||||
vo.BlockTypeQuestion: NodeTypeQuestionAnswer,
|
||||
vo.BlockTypeBotBreak: NodeTypeBreak,
|
||||
vo.BlockTypeBotLoopSetVariable: NodeTypeVariableAssignerWithinLoop,
|
||||
vo.BlockTypeBotLoop: NodeTypeLoop,
|
||||
vo.BlockTypeBotIntent: NodeTypeIntentDetector,
|
||||
vo.BlockTypeBotDatasetWrite: NodeTypeKnowledgeIndexer,
|
||||
vo.BlockTypeBotInput: NodeTypeInputReceiver,
|
||||
vo.BlockTypeBotBatch: NodeTypeBatch,
|
||||
vo.BlockTypeBotContinue: NodeTypeContinue,
|
||||
vo.BlockTypeBotComment: NodeTypeComment,
|
||||
vo.BlockTypeBotVariableMerge: NodeTypeVariableAggregator,
|
||||
vo.BlockTypeCreateConversation: NodeTypeCreateConversation,
|
||||
vo.BlockTypeBotAssignVariable: NodeTypeVariableAssigner,
|
||||
vo.BlockTypeDatabaseUpdate: NodeTypeDatabaseUpdate,
|
||||
vo.BlockTypeDatabaseSelect: NodeTypeDatabaseQuery,
|
||||
vo.BlockTypeDatabaseDelete: NodeTypeDatabaseDelete,
|
||||
vo.BlockTypeDatabaseInsert: NodeTypeDatabaseInsert,
|
||||
vo.BlockTypeBotHttp: NodeTypeHTTPRequester,
|
||||
vo.BlockTypeConversationUpdate: NodeTypeConversationUpdate,
|
||||
vo.BlockTypeConversationDelete: NodeTypeConversationDelete,
|
||||
vo.BlockTypeJsonSerialization: NodeTypeJsonSerialization,
|
||||
vo.BlockTypeJsonDeserialization: NodeTypeJsonDeserialization,
|
||||
vo.BlockTypeBotDatasetDelete: NodeTypeKnowledgeDeleter,
|
||||
vo.BlockTypeConversationList: NodeTypeConversationList,
|
||||
vo.BlockTypeClearConversationHistory: NodeTypeClearConversationHistory,
|
||||
vo.BlockTypeConversationHistory: NodeTypeConversationHistory,
|
||||
vo.BlockTypeBotMessageList: NodeTypeMessageList,
|
||||
vo.BlockTypeCreateMessage: NodeTypeCreateMessage,
|
||||
vo.BlockTypeEditeMessage: NodeTypeEditMessage,
|
||||
vo.BlockTypeDeleteMessage: NodeTypeDeleteMessage,
|
||||
}
|
||||
var nodeType2BlockType = func() map[NodeType]vo.BlockType {
|
||||
nodeType2BlockType := make(map[NodeType]vo.BlockType, len(blockType2NodeType))
|
||||
for k, v := range blockType2NodeType {
|
||||
nodeType2BlockType[v] = k
|
||||
}
|
||||
return nodeType2BlockType
|
||||
}()
|
||||
|
||||
func BlockType2EntityNodeType(t string) (NodeType, error) {
|
||||
blockType := vo.BlockType(t)
|
||||
if nodeType, ok := blockType2NodeType[blockType]; ok {
|
||||
return nodeType, nil
|
||||
}
|
||||
return "", fmt.Errorf("cannot map block type'%s' to a node type", t)
|
||||
}
|
||||
|
||||
func NodeTypeToAPINodeTemplateType(nodeType NodeType) (workflow.NodeTemplateType, error) {
|
||||
if blockType, ok := nodeType2BlockType[nodeType]; ok {
|
||||
blockTypeInt, err := strconv.ParseInt(string(blockType), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return workflow.NodeTemplateType(blockTypeInt), nil
|
||||
}
|
||||
return workflow.NodeTemplateType(0), fmt.Errorf("cannot map entity node type '%s' to a workflow.NodeTemplateType", nodeType)
|
||||
}
|
||||
|
||||
func NodeTypeToBlockType(nodeType NodeType) (vo.BlockType, error) {
|
||||
if t, ok := nodeType2BlockType[nodeType]; ok {
|
||||
return t, nil
|
||||
}
|
||||
return "", vo.WrapError(errno.ErrSchemaConversionFail,
|
||||
fmt.Errorf("cannot map entity node type '%s' to a block type", nodeType))
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,8 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/i18n"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
)
|
||||
@ -481,7 +483,6 @@ var NodeTypeMetas = []*NodeTypeMeta{
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-List.jpeg",
|
||||
SupportBatch: false, // supportBatch: 1
|
||||
Disabled: true,
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
PreFillZero: true,
|
||||
PostFillNil: true,
|
||||
@ -492,14 +493,13 @@ var NodeTypeMetas = []*NodeTypeMeta{
|
||||
},
|
||||
{
|
||||
ID: 38,
|
||||
Name: "清除上下文",
|
||||
Type: NodeTypeClearMessage,
|
||||
Name: "清空会话历史",
|
||||
Type: NodeTypeClearConversationHistory,
|
||||
Category: "conversation_history", // Mapped from cate_list
|
||||
Desc: "用于清空会话历史,清空后LLM看到的会话历史为空",
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Delete.jpeg",
|
||||
SupportBatch: false, // supportBatch: 1
|
||||
Disabled: true,
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
PreFillZero: true,
|
||||
PostFillNil: true,
|
||||
@ -508,6 +508,25 @@ var NodeTypeMetas = []*NodeTypeMeta{
|
||||
EnUSName: "Clear conversation history",
|
||||
EnUSDescription: "Used to clear conversation history. After clearing, the conversation history visible to the LLM node will be empty.",
|
||||
},
|
||||
|
||||
{
|
||||
ID: 54,
|
||||
Name: "查询会话历史",
|
||||
Type: NodeTypeConversationHistory,
|
||||
Category: "conversation_history", // Mapped from cate_list
|
||||
Desc: "用于查询会话历史,返回LLM可见的会话消息",
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-查询会话历史.jpg",
|
||||
SupportBatch: false,
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
PreFillZero: true,
|
||||
PostFillNil: true,
|
||||
StreamingParadigms: map[StreamingParadigm]bool{Invoke: true},
|
||||
},
|
||||
EnUSName: "Query Conversation History",
|
||||
EnUSDescription: "Used to query conversation history, returns conversation messages visible to the LLM",
|
||||
},
|
||||
|
||||
{
|
||||
ID: 39,
|
||||
Name: "创建会话",
|
||||
@ -517,15 +536,51 @@ var NodeTypeMetas = []*NodeTypeMeta{
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
|
||||
SupportBatch: false, // supportBatch: 1
|
||||
Disabled: true,
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
PreFillZero: true,
|
||||
PostFillNil: true,
|
||||
StreamingParadigms: map[StreamingParadigm]bool{Invoke: true},
|
||||
},
|
||||
EnUSName: "Create conversation",
|
||||
EnUSName: "Create Conversation",
|
||||
EnUSDescription: "This node is used to create a conversation.",
|
||||
},
|
||||
|
||||
{
|
||||
ID: 51,
|
||||
Name: "修改会话",
|
||||
Type: NodeTypeConversationUpdate,
|
||||
Category: "conversation_management", // Mapped from cate_list
|
||||
Desc: "用于修改会话的名字",
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-编辑会话.jpg",
|
||||
SupportBatch: false,
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
PreFillZero: true,
|
||||
PostFillNil: true,
|
||||
StreamingParadigms: map[StreamingParadigm]bool{Invoke: true},
|
||||
},
|
||||
EnUSName: "Edit Conversation",
|
||||
EnUSDescription: "Used to modify the name of a conversation.",
|
||||
},
|
||||
|
||||
{
|
||||
ID: 52,
|
||||
Name: "删除会话",
|
||||
Type: NodeTypeConversationDelete,
|
||||
Category: "conversation_management", // Mapped from cate_list
|
||||
Desc: "用于删除会话",
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-删除会话.jpg",
|
||||
SupportBatch: false,
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
PreFillZero: true,
|
||||
PostFillNil: true,
|
||||
StreamingParadigms: map[StreamingParadigm]bool{Invoke: true},
|
||||
},
|
||||
EnUSName: "Delete Conversation",
|
||||
EnUSDescription: "Used to delete a conversation.",
|
||||
},
|
||||
|
||||
{
|
||||
ID: 40,
|
||||
Name: "变量赋值",
|
||||
@ -632,13 +687,83 @@ var NodeTypeMetas = []*NodeTypeMeta{
|
||||
EnUSName: "Add Data",
|
||||
EnUSDescription: "Add new data records to the table, and insert them into the database after the user enters the data content",
|
||||
},
|
||||
{
|
||||
ID: 53,
|
||||
Name: "查询会话列表",
|
||||
Type: NodeTypeConversationList,
|
||||
Category: "conversation_management",
|
||||
Desc: "用于查询所有会话,包含静态会话、动态会话",
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-查询会话.jpg",
|
||||
SupportBatch: false,
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
PostFillNil: true,
|
||||
StreamingParadigms: map[StreamingParadigm]bool{Invoke: true},
|
||||
},
|
||||
EnUSName: "Query Conversation List",
|
||||
EnUSDescription: "Used to query all conversations, including static conversations and dynamic conversations",
|
||||
},
|
||||
{
|
||||
ID: 55,
|
||||
Name: "创建消息",
|
||||
Type: NodeTypeCreateMessage,
|
||||
Category: "message",
|
||||
Desc: "用于创建消息",
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-创建消息.jpg",
|
||||
SupportBatch: false, // supportBatch: 1
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
PreFillZero: true,
|
||||
PostFillNil: true,
|
||||
StreamingParadigms: map[StreamingParadigm]bool{Invoke: true},
|
||||
},
|
||||
EnUSName: "Create message",
|
||||
EnUSDescription: "Used to create messages",
|
||||
},
|
||||
|
||||
{
|
||||
ID: 56,
|
||||
Name: "修改消息",
|
||||
Type: NodeTypeEditMessage,
|
||||
Category: "message",
|
||||
Desc: "用于修改消息",
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-修改消息.jpg",
|
||||
SupportBatch: false, // supportBatch: 1
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
PreFillZero: true,
|
||||
PostFillNil: true,
|
||||
StreamingParadigms: map[StreamingParadigm]bool{Invoke: true},
|
||||
},
|
||||
EnUSName: "Edit message",
|
||||
EnUSDescription: "Used to edit messages",
|
||||
},
|
||||
|
||||
{
|
||||
ID: 57,
|
||||
Name: "删除消息",
|
||||
Type: NodeTypeDeleteMessage,
|
||||
Category: "message",
|
||||
Desc: "用于删除消息",
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-删除消息.jpg",
|
||||
SupportBatch: false, // supportBatch: 1
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
PreFillZero: true,
|
||||
PostFillNil: true,
|
||||
StreamingParadigms: map[StreamingParadigm]bool{Invoke: true},
|
||||
},
|
||||
EnUSName: "Delete message",
|
||||
EnUSDescription: "Used to delete messages",
|
||||
},
|
||||
|
||||
{
|
||||
ID: 58,
|
||||
Name: "JSON 序列化",
|
||||
Type: NodeTypeJsonSerialization,
|
||||
Category: "utilities",
|
||||
Desc: "用于把变量转化为JSON字符串",
|
||||
Color: "F2B600",
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-to_json.png",
|
||||
SupportBatch: false,
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
@ -656,7 +781,7 @@ var NodeTypeMetas = []*NodeTypeMeta{
|
||||
Type: NodeTypeJsonDeserialization,
|
||||
Category: "utilities",
|
||||
Desc: "用于将JSON字符串解析为变量",
|
||||
Color: "F2B600",
|
||||
Color: "#F2B600",
|
||||
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-from_json.png",
|
||||
SupportBatch: false,
|
||||
ExecutableMeta: ExecutableMeta{
|
||||
@ -862,6 +987,133 @@ const defaultEnUSInitCanvasJsonSchema = `{
|
||||
}
|
||||
}`
|
||||
|
||||
const defaultZhCNInitCanvasJsonSchemaChat = `{
|
||||
"nodes": [{
|
||||
"id": "100001",
|
||||
"type": "1",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"outputs": [{
|
||||
"type": "string",
|
||||
"name": "USER_INPUT",
|
||||
"required": true
|
||||
}, {
|
||||
"type": "string",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"required": false,
|
||||
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
|
||||
"defaultValue": "%s"
|
||||
}],
|
||||
"nodeMeta": {
|
||||
"title": "开始",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start.png",
|
||||
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
|
||||
"subTitle": ""
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"id": "900001",
|
||||
"type": "2",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1000,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"title": "结束",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End.png",
|
||||
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
|
||||
"subTitle": ""
|
||||
},
|
||||
"inputs": {
|
||||
"terminatePlan": "useAnswerContent",
|
||||
"streamingOutput": true,
|
||||
"inputParameters": [{
|
||||
"name": "output",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}`
|
||||
const defaultEnUSInitCanvasJsonSchemaChat = `{
|
||||
"nodes": [{
|
||||
"id": "100001",
|
||||
"type": "1",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"outputs": [{
|
||||
"type": "string",
|
||||
"name": "USER_INPUT",
|
||||
"required": true
|
||||
}, {
|
||||
"type": "string",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"required": false,
|
||||
"description": "The conversation bound to this request will automatically write messages and read conversation history from that conversation.",
|
||||
"defaultValue": "%s"
|
||||
}],
|
||||
"nodeMeta": {
|
||||
"title": "Start",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start.png",
|
||||
"description": "The starting node of the workflow, used to set the information needed to initiate the workflow.",
|
||||
"subTitle": ""
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"id": "900001",
|
||||
"type": "2",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1000,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"title": "End",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End.png",
|
||||
"description": "The final node of the workflow, used to return the result information after the workflow runs.",
|
||||
"subTitle": ""
|
||||
},
|
||||
"inputs": {
|
||||
"terminatePlan": "useAnswerContent",
|
||||
"streamingOutput": true,
|
||||
"inputParameters": [{
|
||||
"name": "output",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}`
|
||||
|
||||
func GetDefaultInitCanvasJsonSchema(locale i18n.Locale) string {
|
||||
return ternary.IFElse(locale == i18n.LocaleEN, defaultEnUSInitCanvasJsonSchema, defaultZhCNInitCanvasJsonSchema)
|
||||
}
|
||||
|
||||
func GetDefaultInitCanvasJsonSchemaChat(locale i18n.Locale, name string) string {
|
||||
return ternary.IFElse(locale == i18n.LocaleEN, fmt.Sprintf(defaultEnUSInitCanvasJsonSchemaChat, name), fmt.Sprintf(defaultZhCNInitCanvasJsonSchemaChat, name))
|
||||
}
|
||||
|
||||
@ -70,15 +70,16 @@ type Data struct {
|
||||
}
|
||||
|
||||
type Inputs struct {
|
||||
InputParameters []*Param `json:"inputParameters"`
|
||||
Content *BlockInput `json:"content"`
|
||||
TerminatePlan *TerminatePlan `json:"terminatePlan,omitempty"`
|
||||
StreamingOutput bool `json:"streamingOutput,omitempty"`
|
||||
CallTransferVoice bool `json:"callTransferVoice,omitempty"`
|
||||
ChatHistoryWriting string `json:"chatHistoryWriting,omitempty"`
|
||||
LLMParam any `json:"llmParam,omitempty"` // The LLMParam type may be one of the LLMParam or IntentDetectorLLMParam type or QALLMParam type
|
||||
FCParam *FCParam `json:"fcParam,omitempty"`
|
||||
SettingOnError *SettingOnError `json:"settingOnError,omitempty"`
|
||||
InputParameters []*Param `json:"inputParameters"`
|
||||
Content *BlockInput `json:"content"`
|
||||
TerminatePlan *TerminatePlan `json:"terminatePlan,omitempty"`
|
||||
StreamingOutput bool `json:"streamingOutput,omitempty"`
|
||||
CallTransferVoice bool `json:"callTransferVoice,omitempty"`
|
||||
ChatHistoryWriting string `json:"chatHistoryWriting,omitempty"`
|
||||
ChatHistorySetting *ChatHistorySetting `json:"chatHistorySetting,omitempty"`
|
||||
LLMParam any `json:"llmParam,omitempty"` // The LLMParam type may be one of the LLMParam or IntentDetectorLLMParam type or QALLMParam type
|
||||
FCParam *FCParam `json:"fcParam,omitempty"`
|
||||
SettingOnError *SettingOnError `json:"settingOnError,omitempty"`
|
||||
|
||||
LoopType LoopType `json:"loopType,omitempty"`
|
||||
LoopCount *BlockInput `json:"loopCount,omitempty"`
|
||||
@ -372,9 +373,8 @@ type DatabaseInfo struct {
|
||||
}
|
||||
|
||||
type IntentDetector struct {
|
||||
ChatHistorySetting *ChatHistorySetting `json:"chatHistorySetting,omitempty"`
|
||||
Intents []*Intent `json:"intents,omitempty"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
Intents []*Intent `json:"intents,omitempty"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
}
|
||||
type ChatHistorySetting struct {
|
||||
EnableChatHistory bool `json:"enableChatHistory,omitempty"`
|
||||
@ -445,37 +445,47 @@ func (b BlockType) String() string {
|
||||
}
|
||||
|
||||
const (
|
||||
BlockTypeBotStart BlockType = "1"
|
||||
BlockTypeBotEnd BlockType = "2"
|
||||
BlockTypeBotLLM BlockType = "3"
|
||||
BlockTypeBotAPI BlockType = "4"
|
||||
BlockTypeBotCode BlockType = "5"
|
||||
BlockTypeBotDataset BlockType = "6"
|
||||
BlockTypeCondition BlockType = "8"
|
||||
BlockTypeBotSubWorkflow BlockType = "9"
|
||||
BlockTypeDatabase BlockType = "12"
|
||||
BlockTypeBotMessage BlockType = "13"
|
||||
BlockTypeBotText BlockType = "15"
|
||||
BlockTypeQuestion BlockType = "18"
|
||||
BlockTypeBotBreak BlockType = "19"
|
||||
BlockTypeBotLoopSetVariable BlockType = "20"
|
||||
BlockTypeBotLoop BlockType = "21"
|
||||
BlockTypeBotIntent BlockType = "22"
|
||||
BlockTypeBotDatasetWrite BlockType = "27"
|
||||
BlockTypeBotInput BlockType = "30"
|
||||
BlockTypeBotBatch BlockType = "28"
|
||||
BlockTypeBotContinue BlockType = "29"
|
||||
BlockTypeBotComment BlockType = "31"
|
||||
BlockTypeBotVariableMerge BlockType = "32"
|
||||
BlockTypeBotAssignVariable BlockType = "40"
|
||||
BlockTypeDatabaseUpdate BlockType = "42"
|
||||
BlockTypeDatabaseSelect BlockType = "43"
|
||||
BlockTypeDatabaseDelete BlockType = "44"
|
||||
BlockTypeBotHttp BlockType = "45"
|
||||
BlockTypeDatabaseInsert BlockType = "46"
|
||||
BlockTypeJsonSerialization BlockType = "58"
|
||||
BlockTypeJsonDeserialization BlockType = "59"
|
||||
BlockTypeBotDatasetDelete BlockType = "60"
|
||||
BlockTypeBotStart BlockType = "1"
|
||||
BlockTypeBotEnd BlockType = "2"
|
||||
BlockTypeBotLLM BlockType = "3"
|
||||
BlockTypeBotAPI BlockType = "4"
|
||||
BlockTypeBotCode BlockType = "5"
|
||||
BlockTypeBotDataset BlockType = "6"
|
||||
BlockTypeCondition BlockType = "8"
|
||||
BlockTypeBotSubWorkflow BlockType = "9"
|
||||
BlockTypeDatabase BlockType = "12"
|
||||
BlockTypeBotMessage BlockType = "13"
|
||||
BlockTypeBotText BlockType = "15"
|
||||
BlockTypeQuestion BlockType = "18"
|
||||
BlockTypeBotBreak BlockType = "19"
|
||||
BlockTypeBotLoopSetVariable BlockType = "20"
|
||||
BlockTypeBotLoop BlockType = "21"
|
||||
BlockTypeBotIntent BlockType = "22"
|
||||
BlockTypeBotDatasetWrite BlockType = "27"
|
||||
BlockTypeBotInput BlockType = "30"
|
||||
BlockTypeBotBatch BlockType = "28"
|
||||
BlockTypeBotContinue BlockType = "29"
|
||||
BlockTypeBotComment BlockType = "31"
|
||||
BlockTypeBotVariableMerge BlockType = "32"
|
||||
BlockTypeBotMessageList BlockType = "37"
|
||||
BlockTypeClearConversationHistory BlockType = "38"
|
||||
BlockTypeCreateConversation BlockType = "39"
|
||||
BlockTypeBotAssignVariable BlockType = "40"
|
||||
BlockTypeDatabaseUpdate BlockType = "42"
|
||||
BlockTypeDatabaseSelect BlockType = "43"
|
||||
BlockTypeDatabaseDelete BlockType = "44"
|
||||
BlockTypeBotHttp BlockType = "45"
|
||||
BlockTypeDatabaseInsert BlockType = "46"
|
||||
BlockTypeConversationList BlockType = "53"
|
||||
BlockTypeConversationUpdate BlockType = "51"
|
||||
BlockTypeConversationDelete BlockType = "52"
|
||||
BlockTypeConversationHistory BlockType = "54"
|
||||
BlockTypeCreateMessage BlockType = "55"
|
||||
BlockTypeEditeMessage BlockType = "56"
|
||||
BlockTypeDeleteMessage BlockType = "57"
|
||||
BlockTypeJsonSerialization BlockType = "58"
|
||||
BlockTypeJsonDeserialization BlockType = "59"
|
||||
BlockTypeBotDatasetDelete BlockType = "60"
|
||||
)
|
||||
|
||||
type VariableType string
|
||||
|
||||
54
backend/domain/workflow/entity/vo/chat_flow_role.go
Normal file
54
backend/domain/workflow/entity/vo/chat_flow_role.go
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package vo
|
||||
|
||||
type ChatFlowRoleCreate struct {
|
||||
WorkflowID int64
|
||||
CreatorID int64
|
||||
Name string
|
||||
Description string
|
||||
AvatarUri string
|
||||
BackgroundImageInfo string
|
||||
OnboardingInfo string
|
||||
SuggestReplyInfo string
|
||||
AudioConfig string
|
||||
UserInputConfig string
|
||||
}
|
||||
|
||||
type ChatFlowRoleUpdate struct {
|
||||
WorkflowID int64
|
||||
Name *string
|
||||
Description *string
|
||||
AvatarUri *string
|
||||
BackgroundImageInfo *string
|
||||
OnboardingInfo *string
|
||||
SuggestReplyInfo *string
|
||||
AudioConfig *string
|
||||
UserInputConfig *string
|
||||
}
|
||||
|
||||
type PublishRolePolicy struct {
|
||||
WorkflowID int64
|
||||
CreatorID int64
|
||||
Version string
|
||||
}
|
||||
|
||||
type CopyRolePolicy struct {
|
||||
SourceID int64
|
||||
TargetID int64
|
||||
CreatorID int64
|
||||
}
|
||||
74
backend/domain/workflow/entity/vo/conversation.go
Normal file
74
backend/domain/workflow/entity/vo/conversation.go
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package vo
|
||||
|
||||
type Env string
|
||||
|
||||
const (
|
||||
Draft Env = "draft"
|
||||
Online Env = "online"
|
||||
)
|
||||
|
||||
type CreateConversationTemplateMeta struct {
|
||||
UserID int64
|
||||
AppID int64
|
||||
SpaceID int64
|
||||
Name string
|
||||
}
|
||||
|
||||
type GetConversationTemplatePolicy struct {
|
||||
AppID *int64
|
||||
Name *string
|
||||
Version *string
|
||||
TemplateID *int64
|
||||
}
|
||||
|
||||
type ListConversationTemplatePolicy struct {
|
||||
AppID int64
|
||||
Page *Page
|
||||
NameLike *string
|
||||
Version *string
|
||||
}
|
||||
|
||||
type ListConversationMeta struct {
|
||||
APPID int64
|
||||
UserID int64
|
||||
ConnectorID int64
|
||||
}
|
||||
|
||||
type ListConversationPolicy struct {
|
||||
ListConversationMeta
|
||||
|
||||
Page *Page
|
||||
NameLike *string
|
||||
Version *string
|
||||
}
|
||||
|
||||
type CreateStaticConversation struct {
|
||||
AppID int64
|
||||
UserID int64
|
||||
ConnectorID int64
|
||||
|
||||
TemplateID int64
|
||||
}
|
||||
type CreateDynamicConversation struct {
|
||||
AppID int64
|
||||
UserID int64
|
||||
ConnectorID int64
|
||||
|
||||
Name string
|
||||
}
|
||||
@ -16,22 +16,27 @@
|
||||
|
||||
package vo
|
||||
|
||||
import "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
|
||||
type ExecuteConfig struct {
|
||||
ID int64
|
||||
From Locator
|
||||
Version string
|
||||
CommitID string
|
||||
Operator int64
|
||||
Mode ExecuteMode
|
||||
AppID *int64
|
||||
AgentID *int64
|
||||
ConnectorID int64
|
||||
ConnectorUID string
|
||||
TaskType TaskType
|
||||
SyncPattern SyncPattern
|
||||
InputFailFast bool // whether to fail fast if input conversion has warnings
|
||||
BizType BizType
|
||||
Cancellable bool
|
||||
ID int64
|
||||
From Locator
|
||||
Version string
|
||||
CommitID string
|
||||
Operator int64
|
||||
Mode ExecuteMode
|
||||
AppID *int64
|
||||
AgentID *int64
|
||||
ConnectorID int64
|
||||
ConnectorUID string
|
||||
TaskType TaskType
|
||||
SyncPattern SyncPattern
|
||||
InputFailFast bool // whether to fail fast if input conversion has warnings
|
||||
BizType BizType
|
||||
Cancellable bool
|
||||
WorkflowMode WorkflowMode
|
||||
RoundID *int64 // if workflow is chat flow, conversation round id is required
|
||||
ConversationID *int64 // if workflow is chat flow, conversation id is required
|
||||
}
|
||||
|
||||
type ExecuteMode string
|
||||
@ -42,6 +47,8 @@ const (
|
||||
ExecuteModeNodeDebug ExecuteMode = "node_debug"
|
||||
)
|
||||
|
||||
type WorkflowMode = workflow.WorkflowMode
|
||||
|
||||
type TaskType string
|
||||
|
||||
const (
|
||||
|
||||
@ -80,4 +80,5 @@ type MetaQuery struct {
|
||||
LibOnly bool
|
||||
NeedTotalNumber bool
|
||||
DescByUpdate bool
|
||||
Mode *workflow.WorkflowMode
|
||||
}
|
||||
|
||||
@ -20,11 +20,11 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination ../../internal/mock/domain/workflow/interface.go --package mockWorkflow -source interface.go
|
||||
@ -38,12 +38,21 @@ type Service interface {
|
||||
Publish(ctx context.Context, policy *vo.PublishPolicy) (err error)
|
||||
UpdateMeta(ctx context.Context, id int64, metaUpdate *vo.MetaUpdate) (err error)
|
||||
CopyWorkflow(ctx context.Context, workflowID int64, policy vo.CopyWorkflowPolicy) (*entity.Workflow, error)
|
||||
WorkflowSchemaCheck(ctx context.Context, wf *entity.Workflow, checks []workflow.CheckType) ([]*workflow.CheckResult, error)
|
||||
|
||||
QueryNodeProperties(ctx context.Context, id int64) (map[string]*vo.NodeProperty, error) // only draft
|
||||
ValidateTree(ctx context.Context, id int64, validateConfig vo.ValidateTreeConfig) ([]*workflow.ValidateTreeInfo, error)
|
||||
|
||||
GetWorkflowReference(ctx context.Context, id int64) (map[int64]*vo.Meta, error)
|
||||
|
||||
CreateChatFlowRole(ctx context.Context, role *vo.ChatFlowRoleCreate) (int64, error)
|
||||
UpdateChatFlowRole(ctx context.Context, workflowID int64, role *vo.ChatFlowRoleUpdate) error
|
||||
GetChatFlowRole(ctx context.Context, workflowID int64, version string) (*entity.ChatFlowRole, error)
|
||||
DeleteChatFlowRole(ctx context.Context, id int64, workflowID int64) error
|
||||
PublishChatFlowRole(ctx context.Context, policy *vo.PublishRolePolicy) error
|
||||
CopyChatFlowRole(ctx context.Context, policy *vo.CopyRolePolicy) error
|
||||
GetWorkflowVersionsByConnector(ctx context.Context, connectorID, workflowID int64, limit int) ([]string, error)
|
||||
|
||||
Executable
|
||||
AsTool
|
||||
|
||||
@ -52,17 +61,24 @@ type Service interface {
|
||||
DuplicateWorkflowsByAppID(ctx context.Context, sourceAPPID, targetAppID int64, related vo.ExternalResourceRelated) error
|
||||
GetWorkflowDependenceResource(ctx context.Context, workflowID int64) (*vo.DependenceResource, error)
|
||||
SyncRelatedWorkflowResources(ctx context.Context, appID int64, relatedWorkflows map[int64]entity.IDVersionPair, related vo.ExternalResourceRelated) error
|
||||
|
||||
ConversationService
|
||||
}
|
||||
|
||||
type Repository interface {
|
||||
CreateMeta(ctx context.Context, meta *vo.Meta) (int64, error)
|
||||
CreateVersion(ctx context.Context, id int64, info *vo.VersionInfo, newRefs map[entity.WorkflowReferenceKey]struct{}) (err error)
|
||||
CreateOrUpdateDraft(ctx context.Context, id int64, draft *vo.DraftInfo) error
|
||||
CreateChatFlowRoleConfig(ctx context.Context, chatFlowRole *entity.ChatFlowRole) (int64, error)
|
||||
UpdateChatFlowRoleConfig(ctx context.Context, workflowID int64, chatFlowRole *vo.ChatFlowRoleUpdate) error
|
||||
GetChatFlowRoleConfig(ctx context.Context, workflowID int64, version string) (*entity.ChatFlowRole, error, bool)
|
||||
DeleteChatFlowRoleConfig(ctx context.Context, id int64, workflowID int64) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
MDelete(ctx context.Context, ids []int64) error
|
||||
GetMeta(ctx context.Context, id int64) (*vo.Meta, error)
|
||||
UpdateMeta(ctx context.Context, id int64, metaUpdate *vo.MetaUpdate) error
|
||||
GetVersion(ctx context.Context, id int64, version string) (*vo.VersionInfo, error)
|
||||
GetVersionListByConnectorAndWorkflowID(ctx context.Context, connectorID, workflowID int64, limit int) ([]string, error)
|
||||
|
||||
GetEntity(ctx context.Context, policy *vo.GetPolicy) (*entity.Workflow, error)
|
||||
|
||||
@ -94,8 +110,11 @@ type Repository interface {
|
||||
|
||||
IsApplicationConnectorWorkflowVersion(ctx context.Context, connectorID, workflowID int64, version string) (b bool, err error)
|
||||
|
||||
GetObjectUrl(ctx context.Context, objectKey string, opts ...storage.GetOptFn) (string, error)
|
||||
|
||||
compose.CheckPointStore
|
||||
idgen.IDGenerator
|
||||
ConversationRepository
|
||||
}
|
||||
|
||||
var repositorySingleton Repository
|
||||
|
||||
@ -210,33 +210,43 @@ func normalizePorts(connections []*compose.Connection, nodeMap map[string]*vo.No
|
||||
}
|
||||
|
||||
var blockTypeToNodeSchema = map[vo.BlockType]func(*vo.Node, ...OptionFn) (*compose.NodeSchema, error){
|
||||
vo.BlockTypeBotStart: toEntryNodeSchema,
|
||||
vo.BlockTypeBotEnd: toExitNodeSchema,
|
||||
vo.BlockTypeBotLLM: toLLMNodeSchema,
|
||||
vo.BlockTypeBotLoopSetVariable: toLoopSetVariableNodeSchema,
|
||||
vo.BlockTypeBotBreak: toBreakNodeSchema,
|
||||
vo.BlockTypeBotContinue: toContinueNodeSchema,
|
||||
vo.BlockTypeCondition: toSelectorNodeSchema,
|
||||
vo.BlockTypeBotText: toTextProcessorNodeSchema,
|
||||
vo.BlockTypeBotIntent: toIntentDetectorSchema,
|
||||
vo.BlockTypeDatabase: toDatabaseCustomSQLSchema,
|
||||
vo.BlockTypeDatabaseSelect: toDatabaseQuerySchema,
|
||||
vo.BlockTypeDatabaseInsert: toDatabaseInsertSchema,
|
||||
vo.BlockTypeDatabaseDelete: toDatabaseDeleteSchema,
|
||||
vo.BlockTypeDatabaseUpdate: toDatabaseUpdateSchema,
|
||||
vo.BlockTypeBotHttp: toHttpRequesterSchema,
|
||||
vo.BlockTypeBotDatasetWrite: toKnowledgeIndexerSchema,
|
||||
vo.BlockTypeBotDatasetDelete: toKnowledgeDeleterSchema,
|
||||
vo.BlockTypeBotDataset: toKnowledgeRetrieverSchema,
|
||||
vo.BlockTypeBotAssignVariable: toVariableAssignerSchema,
|
||||
vo.BlockTypeBotCode: toCodeRunnerSchema,
|
||||
vo.BlockTypeBotAPI: toPluginSchema,
|
||||
vo.BlockTypeBotVariableMerge: toVariableAggregatorSchema,
|
||||
vo.BlockTypeBotInput: toInputReceiverSchema,
|
||||
vo.BlockTypeBotMessage: toOutputEmitterNodeSchema,
|
||||
vo.BlockTypeQuestion: toQASchema,
|
||||
vo.BlockTypeJsonSerialization: toJSONSerializeSchema,
|
||||
vo.BlockTypeJsonDeserialization: toJSONDeserializeSchema,
|
||||
vo.BlockTypeBotStart: toEntryNodeSchema,
|
||||
vo.BlockTypeBotEnd: toExitNodeSchema,
|
||||
vo.BlockTypeBotLLM: toLLMNodeSchema,
|
||||
vo.BlockTypeBotLoopSetVariable: toLoopSetVariableNodeSchema,
|
||||
vo.BlockTypeBotBreak: toBreakNodeSchema,
|
||||
vo.BlockTypeBotContinue: toContinueNodeSchema,
|
||||
vo.BlockTypeCondition: toSelectorNodeSchema,
|
||||
vo.BlockTypeBotText: toTextProcessorNodeSchema,
|
||||
vo.BlockTypeBotIntent: toIntentDetectorSchema,
|
||||
vo.BlockTypeDatabase: toDatabaseCustomSQLSchema,
|
||||
vo.BlockTypeDatabaseSelect: toDatabaseQuerySchema,
|
||||
vo.BlockTypeDatabaseInsert: toDatabaseInsertSchema,
|
||||
vo.BlockTypeDatabaseDelete: toDatabaseDeleteSchema,
|
||||
vo.BlockTypeDatabaseUpdate: toDatabaseUpdateSchema,
|
||||
vo.BlockTypeBotHttp: toHttpRequesterSchema,
|
||||
vo.BlockTypeBotDatasetWrite: toKnowledgeIndexerSchema,
|
||||
vo.BlockTypeBotDatasetDelete: toKnowledgeDeleterSchema,
|
||||
vo.BlockTypeBotDataset: toKnowledgeRetrieverSchema,
|
||||
vo.BlockTypeBotAssignVariable: toVariableAssignerSchema,
|
||||
vo.BlockTypeBotCode: toCodeRunnerSchema,
|
||||
vo.BlockTypeBotAPI: toPluginSchema,
|
||||
vo.BlockTypeBotVariableMerge: toVariableAggregatorSchema,
|
||||
vo.BlockTypeBotInput: toInputReceiverSchema,
|
||||
vo.BlockTypeBotMessage: toOutputEmitterNodeSchema,
|
||||
vo.BlockTypeQuestion: toQASchema,
|
||||
vo.BlockTypeJsonSerialization: toJSONSerializeSchema,
|
||||
vo.BlockTypeJsonDeserialization: toJSONDeserializeSchema,
|
||||
vo.BlockTypeCreateConversation: toCreateConversationSchema,
|
||||
vo.BlockTypeConversationUpdate: toConversationUpdateSchema,
|
||||
vo.BlockTypeConversationDelete: toConversationDeleteSchema,
|
||||
vo.BlockTypeConversationList: toConversationListSchema,
|
||||
vo.BlockTypeClearConversationHistory: toClearConversationHistorySchema,
|
||||
vo.BlockTypeConversationHistory: toConversationHistorySchema,
|
||||
vo.BlockTypeCreateMessage: toCreateMessageSchema,
|
||||
vo.BlockTypeBotMessageList: toMessageListSchema,
|
||||
vo.BlockTypeDeleteMessage: toDeleteMessageSchema,
|
||||
vo.BlockTypeEditeMessage: toEditMessageSchema,
|
||||
}
|
||||
|
||||
var blockTypeToSkip = map[vo.BlockType]bool{
|
||||
@ -1110,6 +1120,10 @@ func toIntentDetectorSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, err
|
||||
ns.SetConfigKV("IsFastMode", true)
|
||||
}
|
||||
|
||||
if n.Data.Inputs.ChatHistorySetting != nil {
|
||||
ns.SetConfigKV("ChatHistorySetting", n.Data.Inputs.ChatHistorySetting)
|
||||
}
|
||||
|
||||
if err = SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1394,11 +1408,10 @@ func toHttpRequesterSchema(n *vo.Node, opts ...OptionFn) (*compose.NodeSchema, e
|
||||
formDataVars := make([]string, 0)
|
||||
for i := range inputs.Body.BodyData.FormData.Data {
|
||||
p := inputs.Body.BodyData.FormData.Data[i]
|
||||
formDataVars = append(formDataVars, p.Name)
|
||||
if p.Input.Type == vo.VariableTypeString && p.Input.AssistType > vo.AssistTypeNotSet && p.Input.AssistType < vo.AssistTypeTime {
|
||||
bodyConfig.FormDataConfig.FileTypeMapping[p.Name] = true
|
||||
formDataVars = append(formDataVars, p.Name)
|
||||
}
|
||||
|
||||
}
|
||||
md5FieldMapping.SetBodyFields(formDataVars...)
|
||||
case httprequester.BodyTypeRawText:
|
||||
@ -1508,6 +1521,10 @@ func toKnowledgeRetrieverSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema,
|
||||
}
|
||||
ns.SetConfigKV("KnowledgeIDs", knowledgeIDs)
|
||||
|
||||
if n.Data.Inputs.ChatHistorySetting != nil {
|
||||
ns.SetConfigKV("ChatHistorySetting", n.Data.Inputs.ChatHistorySetting)
|
||||
}
|
||||
|
||||
retrievalStrategy := &knowledge.RetrievalStrategy{}
|
||||
|
||||
var getDesignatedParamContent = func(name string) (any, bool) {
|
||||
@ -1944,6 +1961,180 @@ func toJSONDeserializeSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, er
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func toCreateConversationSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, error) {
|
||||
ns := &compose.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeCreateConversation,
|
||||
Name: n.Data.Meta.Title,
|
||||
}
|
||||
if err := SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func toConversationUpdateSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, error) {
|
||||
ns := &compose.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeConversationUpdate,
|
||||
Name: n.Data.Meta.Title,
|
||||
}
|
||||
if err := SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func toConversationListSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, error) {
|
||||
ns := &compose.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeConversationList,
|
||||
Name: n.Data.Meta.Title,
|
||||
}
|
||||
|
||||
if err := SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func toCreateMessageSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, error) {
|
||||
ns := &compose.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeCreateMessage,
|
||||
Name: n.Data.Meta.Title,
|
||||
}
|
||||
|
||||
if err := SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func toMessageListSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, error) {
|
||||
ns := &compose.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeMessageList,
|
||||
Name: n.Data.Meta.Title,
|
||||
}
|
||||
|
||||
if err := SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func toDeleteMessageSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, error) {
|
||||
ns := &compose.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeDeleteMessage,
|
||||
Name: n.Data.Meta.Title,
|
||||
}
|
||||
|
||||
if err := SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func toEditMessageSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, error) {
|
||||
ns := &compose.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeEditMessage,
|
||||
Name: n.Data.Meta.Title,
|
||||
}
|
||||
|
||||
if err := SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func toConversationHistorySchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, error) {
|
||||
ns := &compose.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeConversationHistory,
|
||||
Name: n.Data.Meta.Title,
|
||||
}
|
||||
if err := SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func toClearConversationHistorySchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, error) {
|
||||
ns := &compose.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeClearConversationHistory,
|
||||
Name: n.Data.Meta.Title,
|
||||
}
|
||||
if err := SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func toConversationDeleteSchema(n *vo.Node, _ ...OptionFn) (*compose.NodeSchema, error) {
|
||||
ns := &compose.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeConversationDelete,
|
||||
Name: n.Data.Meta.Title,
|
||||
}
|
||||
if err := SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func buildClauseGroupFromCondition(condition *vo.DBCondition) (*database.ClauseGroup, error) {
|
||||
clauseGroup := &database.ClauseGroup{}
|
||||
if len(condition.ConditionList) == 1 {
|
||||
|
||||
@ -495,7 +495,14 @@ func LLMParamsToLLMParam(params vo.LLMParam) (*model.LLMParams, error) {
|
||||
case "systemPrompt":
|
||||
strVal := param.Input.Value.Content.(string)
|
||||
p.SystemPrompt = strVal
|
||||
case "chatHistoryRound", "generationDiversity", "frequencyPenalty", "presencePenalty":
|
||||
case "chatHistoryRound":
|
||||
strVal := param.Input.Value.Content.(string)
|
||||
int64Val, err := strconv.ParseInt(strVal, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.ChatHistoryRound = int64Val
|
||||
case "generationDiversity", "frequencyPenalty", "presencePenalty":
|
||||
// do nothing
|
||||
case "topP":
|
||||
strVal := param.Input.Value.Content.(string)
|
||||
|
||||
@ -0,0 +1,93 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "100001",
|
||||
"type": "1",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 13.818572856225469,
|
||||
"y": -37.20384999753011
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"title": "开始",
|
||||
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
|
||||
"subTitle": ""
|
||||
},
|
||||
"settings": null,
|
||||
"version": "",
|
||||
"outputs": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "USER_INPUT",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"required": false,
|
||||
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
|
||||
"defaultValue": "Default"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "input",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"trigger_parameters": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "900001",
|
||||
"type": "2",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 642.9671427865745,
|
||||
"y": -37.20384999753011
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "结束"
|
||||
},
|
||||
"inputs": {
|
||||
"terminatePlan": "returnVariables",
|
||||
"inputParameters": [
|
||||
{
|
||||
"name": "output",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "100001",
|
||||
"name": "input"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "900001"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
{
|
||||
"nodes": [{
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "开始"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "USER_INPUT",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}, {
|
||||
"defaultValue": "Default",
|
||||
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}],
|
||||
"trigger_parameters": []
|
||||
},
|
||||
"edges": null,
|
||||
"id": "100001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"type": "1"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": "{{output}}",
|
||||
"type": "literal"
|
||||
}
|
||||
},
|
||||
"inputParameters": [{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "100001",
|
||||
"name": "USER_INPUT",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "output"
|
||||
}],
|
||||
"streamingOutput": true,
|
||||
"terminatePlan": "useAnswerContent"
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "结束"
|
||||
}
|
||||
},
|
||||
"edges": null,
|
||||
"id": "900001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1000,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"type": "2"
|
||||
}],
|
||||
"edges": [{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "900001",
|
||||
"sourcePortID": ""
|
||||
}],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,193 @@
|
||||
{
|
||||
"nodes": [{
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "开始"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "USER_INPUT",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}, {
|
||||
"defaultValue": "Default",
|
||||
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}],
|
||||
"trigger_parameters": []
|
||||
},
|
||||
"edges": null,
|
||||
"id": "100001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"type": "1"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": "{{output}}",
|
||||
"type": "literal"
|
||||
}
|
||||
},
|
||||
"inputParameters": [{
|
||||
"input": {
|
||||
"schema": {
|
||||
"schema": [{
|
||||
"name": "conversationName",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "conversationId",
|
||||
"type": "string"
|
||||
}],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "list",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "107363",
|
||||
"name": "conversationList",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 103
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "output"
|
||||
}],
|
||||
"streamingOutput": true,
|
||||
"terminatePlan": "useAnswerContent"
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "结束"
|
||||
}
|
||||
},
|
||||
"edges": null,
|
||||
"id": "900001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1058,
|
||||
"y": -13
|
||||
}
|
||||
},
|
||||
"type": "2"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": []
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "用于查询所有会话,包含静态会话、动态会话",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-查询会话.jpg",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "查询会话列表",
|
||||
"title": "查询会话列表"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "conversationList",
|
||||
"schema": {
|
||||
"schema": [{
|
||||
"name": "conversationName",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "conversationId",
|
||||
"type": "string"
|
||||
}],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "list"
|
||||
}]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "107363",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 561,
|
||||
"y": 186
|
||||
}
|
||||
},
|
||||
"type": "53"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "100001",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "conversationName"
|
||||
}]
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "用于创建会话",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "创建会话",
|
||||
"title": "创建会话"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "isSuccess",
|
||||
"type": "boolean"
|
||||
}, {
|
||||
"name": "isExisted",
|
||||
"type": "boolean"
|
||||
}, {
|
||||
"name": "conversationId",
|
||||
"type": "string"
|
||||
}]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "110245",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 487,
|
||||
"y": -196
|
||||
}
|
||||
},
|
||||
"type": "39"
|
||||
}],
|
||||
"edges": [{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "110245",
|
||||
"sourcePortID": ""
|
||||
}, {
|
||||
"sourceNodeID": "107363",
|
||||
"targetNodeID": "900001",
|
||||
"sourcePortID": ""
|
||||
}, {
|
||||
"sourceNodeID": "110245",
|
||||
"targetNodeID": "107363",
|
||||
"sourcePortID": ""
|
||||
}],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,137 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "100001",
|
||||
"type": "1",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 180,
|
||||
"y": 13.700000000000003
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "开始"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "input",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"trigger_parameters": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "900001",
|
||||
"type": "2",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1100,
|
||||
"y": 0.7000000000000028
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "结束"
|
||||
},
|
||||
"inputs": {
|
||||
"terminatePlan": "returnVariables",
|
||||
"inputParameters": [
|
||||
{
|
||||
"name": "output",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "163698",
|
||||
"name": "conversationId"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "163698",
|
||||
"type": "39",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 640,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"outputs": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "isSuccess"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "isExisted"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "conversationId"
|
||||
}
|
||||
],
|
||||
"nodeMeta": {
|
||||
"title": "创建会话",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
|
||||
"description": "用于创建会话",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "创建会话"
|
||||
},
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"name": "conversationName",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "100001",
|
||||
"name": "input"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "163698"
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "163698",
|
||||
"targetNodeID": "900001"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "100001",
|
||||
"type": "1",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": -13.523809523809522,
|
||||
"y": -25.294372294372295
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "开始"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "input",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"trigger_parameters": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "900001",
|
||||
"type": "2",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 890.3549783549786,
|
||||
"y": -71.48917748917748
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "结束"
|
||||
},
|
||||
"inputs": {
|
||||
"terminatePlan": "returnVariables",
|
||||
"inputParameters": [
|
||||
{
|
||||
"name": "output",
|
||||
"input": {
|
||||
"type": "boolean",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "118024",
|
||||
"name": "isSuccess"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "118024",
|
||||
"type": "52",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 423.6623376623378,
|
||||
"y": -126.39999999999999
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"outputs": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "isSuccess"
|
||||
}
|
||||
],
|
||||
"nodeMeta": {
|
||||
"title": "删除会话",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-删除会话.jpg",
|
||||
"description": "用于删除会话",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "删除会话"
|
||||
},
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"name": "conversationName",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "100001",
|
||||
"name": "input"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "118024"
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "118024",
|
||||
"targetNodeID": "900001"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,191 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "100001",
|
||||
"type": "1",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": -243.67931247880136,
|
||||
"y": -233.598184501318
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "开始"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "input",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"trigger_parameters": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "900001",
|
||||
"type": "2",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 911.2952705396514,
|
||||
"y": -331.2250749763467
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "结束"
|
||||
},
|
||||
"inputs": {
|
||||
"terminatePlan": "returnVariables",
|
||||
"inputParameters": [
|
||||
{
|
||||
"name": "output",
|
||||
"input": {
|
||||
"value": {
|
||||
"type": "object_ref"
|
||||
},
|
||||
"type": "object",
|
||||
"schema": [
|
||||
{
|
||||
"name": "isSuccess",
|
||||
"input": {
|
||||
"type": "boolean",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "122336",
|
||||
"name": "isSuccess"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "isExisted",
|
||||
"input": {
|
||||
"type": "boolean",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "122336",
|
||||
"name": "isExisted"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "conversationId",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "122336",
|
||||
"name": "conversationId"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "122336",
|
||||
"type": "51",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 343.08704991877585,
|
||||
"y": -462.38794621339696
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"outputs": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "isSuccess"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "isExisted"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "conversationId"
|
||||
}
|
||||
],
|
||||
"nodeMeta": {
|
||||
"title": "修改会话",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-编辑会话.jpg",
|
||||
"description": "用于修改会话的名字",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "修改会话"
|
||||
},
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"name": "conversationName",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "literal",
|
||||
"content": "template_v1",
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "newConversationName",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "literal",
|
||||
"content": "new",
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "122336"
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "122336",
|
||||
"targetNodeID": "900001"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,262 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "100001",
|
||||
"type": "1",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 180,
|
||||
"y": 13.700000000000003
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "开始"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "input",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "new_name",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"trigger_parameters": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "900001",
|
||||
"type": "2",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1560,
|
||||
"y": 0.7000000000000028
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "结束"
|
||||
},
|
||||
"inputs": {
|
||||
"terminatePlan": "returnVariables",
|
||||
"inputParameters": [
|
||||
{
|
||||
"name": "obj",
|
||||
"input": {
|
||||
"value": {
|
||||
"type": "object_ref"
|
||||
},
|
||||
"type": "object",
|
||||
"schema": [
|
||||
{
|
||||
"name": "isSuccess",
|
||||
"input": {
|
||||
"type": "boolean",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "193175",
|
||||
"name": "isSuccess"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "isExisted",
|
||||
"input": {
|
||||
"type": "boolean",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "193175",
|
||||
"name": "isExisted"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "conversationId",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "193175",
|
||||
"name": "conversationId"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "139551",
|
||||
"type": "39",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 627.929589270746,
|
||||
"y": -36.21123218776195
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"outputs": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "isSuccess"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "isExisted"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "conversationId"
|
||||
}
|
||||
],
|
||||
"nodeMeta": {
|
||||
"title": "创建会话",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
|
||||
"description": "用于创建会话",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "创建会话"
|
||||
},
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"name": "conversationName",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "100001",
|
||||
"name": "input"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "193175",
|
||||
"type": "51",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1100,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"outputs": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "isSuccess"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "isExisted"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "conversationId"
|
||||
}
|
||||
],
|
||||
"nodeMeta": {
|
||||
"title": "修改会话",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-编辑会话.jpg",
|
||||
"description": "用于修改会话的名字",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "修改会话"
|
||||
},
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"name": "conversationName",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "100001",
|
||||
"name": "input"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "newConversationName",
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"type": "ref",
|
||||
"content": {
|
||||
"source": "block-output",
|
||||
"blockID": "100001",
|
||||
"name": "new_name"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "139551"
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "193175",
|
||||
"targetNodeID": "900001"
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "139551",
|
||||
"targetNodeID": "193175"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,234 @@
|
||||
{
|
||||
"nodes": [{
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "开始"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "USER_INPUT",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}, {
|
||||
"defaultValue": "Default",
|
||||
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}],
|
||||
"trigger_parameters": []
|
||||
},
|
||||
"edges": null,
|
||||
"id": "100001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"type": "1"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [{
|
||||
"input": {
|
||||
"type": "boolean",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "195185",
|
||||
"name": "isSuccess",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 3
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "output"
|
||||
}, {
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "195185",
|
||||
"name": "message.messageId",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "mID"
|
||||
}],
|
||||
"terminatePlan": "returnVariables"
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "结束"
|
||||
}
|
||||
},
|
||||
"edges": null,
|
||||
"id": "900001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1000,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"type": "2"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "100001",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "conversationName"
|
||||
}, {
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": "user",
|
||||
"type": "literal"
|
||||
}
|
||||
},
|
||||
"name": "role"
|
||||
}, {
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": "1",
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "literal"
|
||||
}
|
||||
},
|
||||
"name": "content"
|
||||
}]
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "用于创建消息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-创建消息.jpg",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "创建消息",
|
||||
"title": "创建消息"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "isSuccess",
|
||||
"type": "boolean"
|
||||
}, {
|
||||
"name": "message",
|
||||
"schema": [{
|
||||
"name": "messageId",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "role",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "contentType",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "content",
|
||||
"type": "string"
|
||||
}],
|
||||
"type": "object"
|
||||
}]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "195185",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 482,
|
||||
"y": -13
|
||||
}
|
||||
},
|
||||
"type": "55"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "100001",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "conversationName"
|
||||
}]
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "用于创建会话",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "创建会话",
|
||||
"title": "创建会话"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "isSuccess",
|
||||
"type": "boolean"
|
||||
}, {
|
||||
"name": "isExisted",
|
||||
"type": "boolean"
|
||||
}, {
|
||||
"name": "conversationId",
|
||||
"type": "string"
|
||||
}]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "121849",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 302,
|
||||
"y": -236
|
||||
}
|
||||
},
|
||||
"type": "39"
|
||||
}],
|
||||
"edges": [{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "121849",
|
||||
"sourcePortID": ""
|
||||
}, {
|
||||
"sourceNodeID": "195185",
|
||||
"targetNodeID": "900001",
|
||||
"sourcePortID": ""
|
||||
}, {
|
||||
"sourceNodeID": "121849",
|
||||
"targetNodeID": "195185",
|
||||
"sourcePortID": ""
|
||||
}],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,310 @@
|
||||
{
|
||||
"nodes": [{
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"nodeMeta": {
|
||||
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "开始"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "USER_INPUT",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}, {
|
||||
"defaultValue": "Default",
|
||||
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}],
|
||||
"trigger_parameters": []
|
||||
},
|
||||
"edges": null,
|
||||
"id": "100001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"type": "1"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [{
|
||||
"input": {
|
||||
"schema": {
|
||||
"schema": [{
|
||||
"name": "messageId",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "role",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "contentType",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "content",
|
||||
"type": "string"
|
||||
}],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "list",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "132703",
|
||||
"name": "messageList",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 103
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "output"
|
||||
}],
|
||||
"terminatePlan": "returnVariables"
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
|
||||
"subTitle": "",
|
||||
"title": "结束"
|
||||
}
|
||||
},
|
||||
"edges": null,
|
||||
"id": "900001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1000,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
"type": "2"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "100001",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "conversationName"
|
||||
}]
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "用于查询消息列表",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-List.jpeg",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "查询消息列表",
|
||||
"title": "查询消息列表"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "messageList",
|
||||
"schema": {
|
||||
"schema": [{
|
||||
"name": "messageId",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "role",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "contentType",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "content",
|
||||
"type": "string"
|
||||
}],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "list"
|
||||
}, {
|
||||
"name": "firstId",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "lastId",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "hasMore",
|
||||
"type": "boolean"
|
||||
}]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "132703",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 514,
|
||||
"y": 96
|
||||
}
|
||||
},
|
||||
"type": "37"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "100001",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "conversationName"
|
||||
}]
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "用于创建会话",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "创建会话",
|
||||
"title": "创建会话"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "isSuccess",
|
||||
"type": "boolean"
|
||||
}, {
|
||||
"name": "isExisted",
|
||||
"type": "boolean"
|
||||
}, {
|
||||
"name": "conversationId",
|
||||
"type": "string"
|
||||
}]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "166724",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 323,
|
||||
"y": -332
|
||||
}
|
||||
},
|
||||
"type": "39"
|
||||
}, {
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "100001",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "conversationName"
|
||||
}, {
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": "user",
|
||||
"type": "literal"
|
||||
}
|
||||
},
|
||||
"name": "role"
|
||||
}, {
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "100001",
|
||||
"name": "USER_INPUT",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "content"
|
||||
}]
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "用于创建消息",
|
||||
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-创建消息.jpg",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "创建消息",
|
||||
"title": "创建消息"
|
||||
},
|
||||
"outputs": [{
|
||||
"name": "isSuccess",
|
||||
"type": "boolean"
|
||||
}, {
|
||||
"name": "message",
|
||||
"schema": [{
|
||||
"name": "messageId",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "role",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "contentType",
|
||||
"type": "string"
|
||||
}, {
|
||||
"name": "content",
|
||||
"type": "string"
|
||||
}],
|
||||
"type": "object"
|
||||
}]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "157061",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 479,
|
||||
"y": -127
|
||||
}
|
||||
},
|
||||
"type": "55"
|
||||
}],
|
||||
"edges": [{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "166724",
|
||||
"sourcePortID": ""
|
||||
}, {
|
||||
"sourceNodeID": "132703",
|
||||
"targetNodeID": "900001",
|
||||
"sourcePortID": ""
|
||||
}, {
|
||||
"sourceNodeID": "157061",
|
||||
"targetNodeID": "132703",
|
||||
"sourcePortID": ""
|
||||
}, {
|
||||
"sourceNodeID": "166724",
|
||||
"targetNodeID": "157061",
|
||||
"sourcePortID": ""
|
||||
}],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -32,7 +32,6 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/llm"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
)
|
||||
|
||||
@ -47,8 +46,6 @@ func (r *WorkflowRunner) designateOptions(ctx context.Context) (context.Context,
|
||||
sw = r.streamWriter
|
||||
)
|
||||
|
||||
const tokenCallbackKey = "token_callback_key"
|
||||
|
||||
if wb.AppID != nil && exeCfg.AppID == nil {
|
||||
exeCfg.AppID = wb.AppID
|
||||
}
|
||||
@ -124,12 +121,6 @@ func (r *WorkflowRunner) designateOptions(ctx context.Context) (context.Context,
|
||||
opts = append(opts, einoCompose.WithCheckPointID(strconv.FormatInt(executeID, 10)))
|
||||
}
|
||||
|
||||
if !ctxcache.HasKey(ctx, tokenCallbackKey) {
|
||||
opts = append(opts, einoCompose.WithCallbacks(execute.GetTokenCallbackHandler()))
|
||||
ctx = ctxcache.Init(ctx)
|
||||
ctxcache.Store(ctx, tokenCallbackKey, true)
|
||||
}
|
||||
|
||||
return ctx, opts, nil
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
@ -137,7 +138,11 @@ func (s *NodeSchema) New(ctx context.Context, inner compose.Runnable[map[string]
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return invokableStreamableNodeWO(s, l.Chat, l.ChatStream, withCallbackOutputConverter(l.ToCallbackOutput)), nil
|
||||
initFn := func(ctx context.Context) (context.Context, error) {
|
||||
return ctxcache.Init(ctx), nil
|
||||
}
|
||||
|
||||
return invokableStreamableNodeWO(s, l.Chat, l.ChatStream, withCallbackInputConverter(l.ToCallbackInput), withCallbackOutputConverter(l.ToCallbackOutput), withInit(initFn)), nil
|
||||
case entity.NodeTypeSelector:
|
||||
conf := s.ToSelectorConfig()
|
||||
|
||||
@ -388,7 +393,10 @@ func (s *NodeSchema) New(ctx context.Context, inner compose.Runnable[map[string]
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invokableNode(s, r.Retrieve), nil
|
||||
initFn := func(ctx context.Context) (context.Context, error) {
|
||||
return ctxcache.Init(ctx), nil
|
||||
}
|
||||
return invokableNode(s, r.Retrieve, withCallbackInputConverter(r.ToCallbackInput), withInit(initFn)), nil
|
||||
case entity.NodeTypeKnowledgeDeleter:
|
||||
conf, err := s.ToKnowledgeDeleterConfig()
|
||||
if err != nil {
|
||||
@ -432,6 +440,61 @@ func (s *NodeSchema) New(ctx context.Context, inner compose.Runnable[map[string]
|
||||
return nil, err
|
||||
}
|
||||
return invokableNode(s, r.Create), nil
|
||||
|
||||
case entity.NodeTypeConversationUpdate:
|
||||
r := conversation.NewUpdateConversation(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invokableNode(s, r.Update), nil
|
||||
case entity.NodeTypeConversationList:
|
||||
r, err := conversation.NewConversationList(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invokableNode(s, r.List), nil
|
||||
case entity.NodeTypeConversationDelete:
|
||||
r := conversation.NewDeleteConversation(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invokableNode(s, r.Delete), nil
|
||||
case entity.NodeTypeCreateMessage:
|
||||
conf, err := s.ToCreateMessageConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := conversation.NewCreateMessage(ctx, conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invokableNode(s, r.Create), nil
|
||||
case entity.NodeTypeClearConversationHistory:
|
||||
cfg, err := s.ToClearConversationHistoryConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := conversation.NewClearConversationHistory(ctx, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return invokableNode(s, r.Clear), nil
|
||||
|
||||
case entity.NodeTypeConversationHistory:
|
||||
cfg, err := s.ToConversationHistoryConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := conversation.NewConversationHistory(ctx, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return invokableNode(s, r.HistoryMessages), nil
|
||||
|
||||
case entity.NodeTypeMessageList:
|
||||
conf, err := s.ToMessageListConfig()
|
||||
if err != nil {
|
||||
@ -442,16 +505,26 @@ func (s *NodeSchema) New(ctx context.Context, inner compose.Runnable[map[string]
|
||||
return nil, err
|
||||
}
|
||||
return invokableNode(s, r.List), nil
|
||||
case entity.NodeTypeClearMessage:
|
||||
conf, err := s.ToClearMessageConfig()
|
||||
case entity.NodeTypeDeleteMessage:
|
||||
conf, err := s.ToDeleteMessageConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := conversation.NewClearMessage(ctx, conf)
|
||||
r, err := conversation.NewDeleteMessage(ctx, conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invokableNode(s, r.Clear), nil
|
||||
return invokableNode(s, r.Delete), nil
|
||||
case entity.NodeTypeEditMessage:
|
||||
conf, err := s.ToEditMessageConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := conversation.NewEditMessage(ctx, conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invokableNode(s, r.Edit), nil
|
||||
case entity.NodeTypeIntentDetector:
|
||||
conf, err := s.ToIntentDetectorConfig(ctx)
|
||||
if err != nil {
|
||||
@ -461,8 +534,10 @@ func (s *NodeSchema) New(ctx context.Context, inner compose.Runnable[map[string]
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return invokableNode(s, r.Invoke), nil
|
||||
initFn := func(ctx context.Context) (context.Context, error) {
|
||||
return ctxcache.Init(ctx), nil
|
||||
}
|
||||
return invokableNode(s, r.Invoke, withCallbackInputConverter(r.ToCallbackInput), withInit(initFn)), nil
|
||||
case entity.NodeTypeSubWorkflow:
|
||||
conf, err := s.ToSubWorkflowConfig(ctx, sc.requireCheckPoint)
|
||||
if err != nil {
|
||||
@ -537,6 +612,9 @@ func (s *NodeSchema) IsEnableChatHistory() bool {
|
||||
case entity.NodeTypeIntentDetector:
|
||||
llmParam := mustGetKey[*model.LLMParams]("LLMParams", s.Configs)
|
||||
return llmParam.EnableChatHistory
|
||||
case entity.NodeTypeKnowledgeRetriever:
|
||||
chatHistorySetting := getKeyOrZero[*vo.ChatHistorySetting]("ChatHistorySetting", s.Configs)
|
||||
return chatHistorySetting != nil && chatHistorySetting.EnableChatHistory
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
@ -86,6 +86,8 @@ func init() {
|
||||
_ = compose.RegisterSerializableType[vo.Locator]("wf_locator")
|
||||
_ = compose.RegisterSerializableType[vo.BizType]("biz_type")
|
||||
_ = compose.RegisterSerializableType[*variableassigner.AppVariables]("app_variables")
|
||||
_ = compose.RegisterSerializableType[workflow2.WorkflowMode]("workflow_mode")
|
||||
|
||||
}
|
||||
|
||||
func (s *State) SetAppVariableValue(key string, value any) {
|
||||
|
||||
@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"time"
|
||||
@ -96,6 +97,13 @@ func (s *NodeSchema) ToLLMConfig(ctx context.Context) (*llm.Config, error) {
|
||||
modelWithInfo llm.ModelWithInfo
|
||||
)
|
||||
|
||||
if llmParams.EnableChatHistory {
|
||||
llmConf.ChatHistorySetting = &vo.ChatHistorySetting{
|
||||
EnableChatHistory: llmParams.EnableChatHistory,
|
||||
ChatHistoryRound: llmParams.ChatHistoryRound,
|
||||
}
|
||||
}
|
||||
|
||||
chatModel, info, err = model.GetManager().GetModel(ctx, llmParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -502,6 +510,7 @@ func (s *NodeSchema) ToDatabaseCustomSQLConfig() (*database.CustomSQLConfig, err
|
||||
OutputConfig: s.OutputTypes,
|
||||
CustomSQLExecutor: crossdatabase.GetDatabaseOperator(),
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *NodeSchema) ToDatabaseQueryConfig() (*database.QueryConfig, error) {
|
||||
@ -517,6 +526,7 @@ func (s *NodeSchema) ToDatabaseQueryConfig() (*database.QueryConfig, error) {
|
||||
}
|
||||
|
||||
func (s *NodeSchema) ToDatabaseInsertConfig() (*database.InsertConfig, error) {
|
||||
|
||||
return &database.InsertConfig{
|
||||
DatabaseInfoID: mustGetKey[int64]("DatabaseInfoID", s.Configs),
|
||||
OutputConfig: s.OutputTypes,
|
||||
@ -534,6 +544,7 @@ func (s *NodeSchema) ToDatabaseDeleteConfig() (*database.DeleteConfig, error) {
|
||||
}
|
||||
|
||||
func (s *NodeSchema) ToDatabaseUpdateConfig() (*database.UpdateConfig, error) {
|
||||
|
||||
return &database.UpdateConfig{
|
||||
DatabaseInfoID: mustGetKey[int64]("DatabaseInfoID", s.Configs),
|
||||
ClauseGroup: mustGetKey[*crossdatabase.ClauseGroup]("ClauseGroup", s.Configs),
|
||||
@ -553,9 +564,10 @@ func (s *NodeSchema) ToKnowledgeIndexerConfig() (*knowledge.IndexerConfig, error
|
||||
|
||||
func (s *NodeSchema) ToKnowledgeRetrieveConfig() (*knowledge.RetrieveConfig, error) {
|
||||
return &knowledge.RetrieveConfig{
|
||||
KnowledgeIDs: mustGetKey[[]int64]("KnowledgeIDs", s.Configs),
|
||||
RetrievalStrategy: mustGetKey[*crossknowledge.RetrievalStrategy]("RetrievalStrategy", s.Configs),
|
||||
Retriever: crossknowledge.GetKnowledgeOperator(),
|
||||
KnowledgeIDs: mustGetKey[[]int64]("KnowledgeIDs", s.Configs),
|
||||
RetrievalStrategy: mustGetKey[*crossknowledge.RetrievalStrategy]("RetrievalStrategy", s.Configs),
|
||||
Retriever: crossknowledge.GetKnowledgeOperator(),
|
||||
ChatHistorySetting: getKeyOrZero[*vo.ChatHistorySetting]("ChatHistorySetting", s.Configs),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -573,6 +585,7 @@ func (s *NodeSchema) ToPluginConfig() (*plugin.Config, error) {
|
||||
PluginVersion: mustGetKey[string]("PluginVersion", s.Configs),
|
||||
PluginService: crossplugin.GetPluginService(),
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *NodeSchema) ToCodeRunnerConfig() (*code.Config, error) {
|
||||
@ -586,27 +599,51 @@ func (s *NodeSchema) ToCodeRunnerConfig() (*code.Config, error) {
|
||||
|
||||
func (s *NodeSchema) ToCreateConversationConfig() (*conversation.CreateConversationConfig, error) {
|
||||
return &conversation.CreateConversationConfig{
|
||||
Creator: crossconversation.ConversationManagerImpl,
|
||||
Manager: crossconversation.GetConversationManager(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *NodeSchema) ToClearMessageConfig() (*conversation.ClearMessageConfig, error) {
|
||||
return &conversation.ClearMessageConfig{
|
||||
Clearer: crossconversation.ConversationManagerImpl,
|
||||
func (s *NodeSchema) ToDeleteMessageConfig() (*conversation.DeleteMessageConfig, error) {
|
||||
return &conversation.DeleteMessageConfig{
|
||||
Manager: crossconversation.GetConversationManager(),
|
||||
}, nil
|
||||
}
|
||||
func (s *NodeSchema) ToEditMessageConfig() (*conversation.EditMessageConfig, error) {
|
||||
return &conversation.EditMessageConfig{
|
||||
Manager: crossconversation.GetConversationManager(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *NodeSchema) ToCreateMessageConfig() (*conversation.CreateMessageConfig, error) {
|
||||
return &conversation.CreateMessageConfig{
|
||||
Creator: crossconversation.GetConversationManager(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *NodeSchema) ToMessageListConfig() (*conversation.MessageListConfig, error) {
|
||||
return &conversation.MessageListConfig{
|
||||
Lister: crossconversation.ConversationManagerImpl,
|
||||
Lister: crossconversation.GetConversationManager(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *NodeSchema) ToClearConversationHistoryConfig() (*conversation.ClearConversationHistoryConfig, error) {
|
||||
return &conversation.ClearConversationHistoryConfig{
|
||||
Manager: crossconversation.GetConversationManager(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *NodeSchema) ToConversationHistoryConfig() (*conversation.ConversationHistoryConfig, error) {
|
||||
return &conversation.ConversationHistoryConfig{
|
||||
Manager: crossconversation.GetConversationManager(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *NodeSchema) ToIntentDetectorConfig(ctx context.Context) (*intentdetector.Config, error) {
|
||||
cfg := &intentdetector.Config{
|
||||
Intents: mustGetKey[[]string]("Intents", s.Configs),
|
||||
SystemPrompt: getKeyOrZero[string]("SystemPrompt", s.Configs),
|
||||
IsFastMode: getKeyOrZero[bool]("IsFastMode", s.Configs),
|
||||
Intents: mustGetKey[[]string]("Intents", s.Configs),
|
||||
SystemPrompt: getKeyOrZero[string]("SystemPrompt", s.Configs),
|
||||
IsFastMode: getKeyOrZero[bool]("IsFastMode", s.Configs),
|
||||
ChatHistorySetting: getKeyOrZero[*vo.ChatHistorySetting]("ChatHistorySetting", s.Configs),
|
||||
}
|
||||
|
||||
llmParams := mustGetKey[*model.LLMParams]("LLMParams", s.Configs)
|
||||
|
||||
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type ClearConversationHistoryConfig struct {
|
||||
Manager conversation.ConversationManager
|
||||
}
|
||||
|
||||
type ClearConversationHistory struct {
|
||||
cfg *ClearConversationHistoryConfig
|
||||
}
|
||||
|
||||
func NewClearConversationHistory(_ context.Context, cfg *ClearConversationHistoryConfig) (*ClearConversationHistory, error) {
|
||||
if cfg == nil {
|
||||
return nil, errors.New("config is required")
|
||||
}
|
||||
if cfg.Manager == nil {
|
||||
return nil, errors.New("manager is required")
|
||||
}
|
||||
|
||||
return &ClearConversationHistory{
|
||||
cfg: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *ClearConversationHistory) Clear(ctx context.Context, in map[string]any) (map[string]any, error) {
|
||||
|
||||
var (
|
||||
execCtx = execute.GetExeCtx(ctx)
|
||||
env = ternary.IFElse(execCtx.ExeCfg.Mode == vo.ExecuteModeRelease, vo.Online, vo.Draft)
|
||||
appID = execCtx.ExeCfg.AppID
|
||||
agentID = execCtx.ExeCfg.AgentID
|
||||
connectorID = execCtx.ExeCfg.ConnectorID
|
||||
userID = execCtx.ExeCfg.Operator
|
||||
version = execCtx.ExeCfg.Version
|
||||
)
|
||||
|
||||
if agentID != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, query conversation list is not available"))
|
||||
}
|
||||
if appID == nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("query conversation list node, app id is required"))
|
||||
}
|
||||
|
||||
conversationName, ok := in["conversationName"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversation name is required"))
|
||||
}
|
||||
|
||||
t, existed, err := wf.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
|
||||
AppID: appID,
|
||||
Name: ptr.Of(conversationName),
|
||||
Version: ptr.Of(version),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
var conversationID int64
|
||||
if existed {
|
||||
ret, existed, err := wf.GetRepository().GetStaticConversationByTemplateID(ctx, env, userID, connectorID, t.TemplateID)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
if existed {
|
||||
conversationID = ret.ConversationID
|
||||
}
|
||||
} else {
|
||||
ret, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
if existed {
|
||||
conversationID = ret.ConversationID
|
||||
}
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return map[string]any{
|
||||
"isSuccess": false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
err = c.cfg.Manager.ClearConversationHistory(ctx, &conversation.ClearConversationHistoryReq{
|
||||
ConversationID: conversationID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
return map[string]any{
|
||||
"isSuccess": true,
|
||||
}, nil
|
||||
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
)
|
||||
|
||||
type ClearMessageConfig struct {
|
||||
Clearer conversation.ConversationManager
|
||||
}
|
||||
|
||||
type MessageClear struct {
|
||||
config *ClearMessageConfig
|
||||
}
|
||||
|
||||
func NewClearMessage(ctx context.Context, cfg *ClearMessageConfig) (*MessageClear, error) {
|
||||
if cfg == nil {
|
||||
return nil, errors.New("config is required")
|
||||
}
|
||||
if cfg.Clearer == nil {
|
||||
return nil, errors.New("clearer is required")
|
||||
}
|
||||
|
||||
return &MessageClear{
|
||||
config: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *MessageClear) Clear(ctx context.Context, input map[string]any) (map[string]any, error) {
|
||||
name, ok := nodes.TakeMapValue(input, compose.FieldPath{"ConversationName"})
|
||||
if !ok {
|
||||
return nil, errors.New("input map should contains 'ConversationName' key ")
|
||||
}
|
||||
response, err := c.config.Clearer.ClearMessage(ctx, &conversation.ClearMessageRequest{
|
||||
Name: name.(string),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{
|
||||
"isSuccess": response.IsSuccess,
|
||||
}, nil
|
||||
}
|
||||
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
oceanworkflow "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
const chatHistoryKey contextKey = "chatHistory"
|
||||
|
||||
func ConvertMessageToString(ctx context.Context, msg *conversation.Message) (string, error) {
|
||||
if msg.MultiContent != nil {
|
||||
var textContents []string
|
||||
var otherContents []string
|
||||
for _, m := range msg.MultiContent {
|
||||
if m.Text != nil {
|
||||
textContents = append(textContents, ptr.From(m.Text))
|
||||
} else if m.Uri != nil {
|
||||
url, err := workflow.GetRepository().GetObjectUrl(ctx, ptr.From(m.Uri))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
otherContents = append(otherContents, url)
|
||||
}
|
||||
}
|
||||
|
||||
var allParts []string
|
||||
if len(textContents) > 0 {
|
||||
allParts = append(allParts, textContents...)
|
||||
}
|
||||
if len(otherContents) > 0 {
|
||||
allParts = append(allParts, otherContents...)
|
||||
}
|
||||
return strings.Join(allParts, ","), nil
|
||||
} else if msg.Text != nil {
|
||||
return ptr.From(msg.Text), nil
|
||||
} else {
|
||||
return "", vo.WrapError(errno.ErrInvalidParameter, errors.New("message is invalid"))
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertMessageToSchema(ctx context.Context, msg *conversation.Message) (*schema.Message, error) {
|
||||
schemaMsg := &schema.Message{}
|
||||
|
||||
switch msg.Role {
|
||||
case "user":
|
||||
schemaMsg.Role = schema.User
|
||||
case "assistant":
|
||||
schemaMsg.Role = schema.Assistant
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown role: %s", msg.Role)
|
||||
}
|
||||
|
||||
if msg.Text != nil && *msg.Text != "" {
|
||||
schemaMsg.Content = *msg.Text
|
||||
return schemaMsg, nil
|
||||
}
|
||||
|
||||
if len(msg.MultiContent) > 0 {
|
||||
multiContent := make([]schema.ChatMessagePart, 0, len(msg.MultiContent))
|
||||
for _, part := range msg.MultiContent {
|
||||
schemaPart, err := convertContentPart(ctx, part)
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "failed to convert content part, skipping: %v", err)
|
||||
continue
|
||||
}
|
||||
multiContent = append(multiContent, schemaPart)
|
||||
}
|
||||
schemaMsg.MultiContent = multiContent
|
||||
return schemaMsg, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("message has no content")
|
||||
}
|
||||
|
||||
func convertContentPart(ctx context.Context, part *conversation.Content) (schema.ChatMessagePart, error) {
|
||||
schemaPart := schema.ChatMessagePart{}
|
||||
uri := ""
|
||||
if part.Uri != nil {
|
||||
uri = *part.Uri
|
||||
}
|
||||
|
||||
switch part.Type {
|
||||
case "text":
|
||||
schemaPart.Type = schema.ChatMessagePartTypeText
|
||||
if part.Text == nil || *part.Text == "" {
|
||||
return schema.ChatMessagePart{}, fmt.Errorf("text is empty for text content part type")
|
||||
}
|
||||
schemaPart.Text = *part.Text
|
||||
case "image":
|
||||
schemaPart.Type = schema.ChatMessagePartTypeImageURL
|
||||
url, err := workflow.GetRepository().GetObjectUrl(ctx, uri)
|
||||
if err != nil {
|
||||
return schema.ChatMessagePart{}, fmt.Errorf("failed to get object url: %w", err)
|
||||
}
|
||||
schemaPart.ImageURL = &schema.ChatMessageImageURL{URL: url}
|
||||
case "audio":
|
||||
schemaPart.Type = schema.ChatMessagePartTypeAudioURL
|
||||
url, err := workflow.GetRepository().GetObjectUrl(ctx, uri)
|
||||
if err != nil {
|
||||
return schema.ChatMessagePart{}, fmt.Errorf("failed to get object url: %w", err)
|
||||
}
|
||||
schemaPart.AudioURL = &schema.ChatMessageAudioURL{URL: url}
|
||||
case "video":
|
||||
schemaPart.Type = schema.ChatMessagePartTypeVideoURL
|
||||
url, err := workflow.GetRepository().GetObjectUrl(ctx, uri)
|
||||
if err != nil {
|
||||
return schema.ChatMessagePart{}, fmt.Errorf("failed to get object url: %w", err)
|
||||
}
|
||||
schemaPart.VideoURL = &schema.ChatMessageVideoURL{URL: url}
|
||||
case "file":
|
||||
schemaPart.Type = schema.ChatMessagePartTypeFileURL
|
||||
url, err := workflow.GetRepository().GetObjectUrl(ctx, uri)
|
||||
if err != nil {
|
||||
return schema.ChatMessagePart{}, fmt.Errorf("failed to get object url: %w", err)
|
||||
}
|
||||
schemaPart.FileURL = &schema.ChatMessageFileURL{URL: url}
|
||||
default:
|
||||
return schema.ChatMessagePart{}, fmt.Errorf("unknown content part type: %s", part.Type)
|
||||
}
|
||||
|
||||
if schemaPart.Type != schema.ChatMessagePartTypeText && uri == "" {
|
||||
return schema.ChatMessagePart{}, fmt.Errorf("uri is empty for non-text content part type %s", part.Type)
|
||||
}
|
||||
|
||||
return schemaPart, nil
|
||||
}
|
||||
|
||||
func GetConversationHistoryFromCtx(ctx context.Context, rounds int64) ([]any, error) {
|
||||
exeCtx := execute.GetExeCtx(ctx)
|
||||
if exeCtx == nil {
|
||||
logs.CtxWarnf(ctx, "execute context is nil, skipping chat history")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if exeCtx.ExeCfg.WorkflowMode != oceanworkflow.WorkflowMode_ChatFlow {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
convID := exeCtx.ExeCfg.ConversationID
|
||||
agentID := exeCtx.ExeCfg.AgentID
|
||||
appID := exeCtx.ExeCfg.AppID
|
||||
userID := exeCtx.ExeCfg.Operator
|
||||
|
||||
if convID == nil || *convID == 0 {
|
||||
logs.CtxWarnf(ctx, "ConversationID is 0 or nil, skipping chat history")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var appIDVal int64
|
||||
if appID != nil {
|
||||
appIDVal = *appID
|
||||
} else if agentID != nil {
|
||||
appIDVal = *agentID
|
||||
} else {
|
||||
logs.CtxWarnf(ctx, "AppID and AgentID are both nil, skipping chat history")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
runIdsReq := &conversation.GetLatestRunIDsRequest{
|
||||
ConversationID: *convID,
|
||||
AppID: appIDVal,
|
||||
UserID: userID,
|
||||
Rounds: rounds,
|
||||
}
|
||||
|
||||
runIds, err := conversation.GetConversationManager().GetLatestRunIDs(ctx, runIdsReq)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "failed to get conversation history: %v", err)
|
||||
return nil, nil
|
||||
}
|
||||
if len(runIds) <= 1 {
|
||||
return []any{}, nil
|
||||
}
|
||||
runIds = runIds[1:]
|
||||
|
||||
response, err := conversation.GetConversationManager().GetMessagesByRunIDs(ctx, &conversation.GetMessagesByRunIDsRequest{
|
||||
ConversationID: *convID,
|
||||
RunIDs: runIds,
|
||||
})
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "failed to get conversation history: %v", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ctxcache.Store(ctx, chatHistoryKey, response.Messages)
|
||||
messageList := make([]any, 0, len(response.Messages))
|
||||
for _, msg := range response.Messages {
|
||||
content, err := ConvertMessageToString(ctx, msg)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
messageList = append(messageList, map[string]any{
|
||||
"role": msg.Role,
|
||||
"content": content,
|
||||
})
|
||||
}
|
||||
return messageList, nil
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type ConversationList struct {
|
||||
}
|
||||
|
||||
func NewConversationList(_ context.Context) (*ConversationList, error) {
|
||||
return &ConversationList{}, nil
|
||||
}
|
||||
|
||||
type conversationInfo struct {
|
||||
conversationName string
|
||||
conversationId string
|
||||
}
|
||||
|
||||
func (c *ConversationList) List(ctx context.Context, _ map[string]any) (map[string]any, error) {
|
||||
var (
|
||||
execCtx = execute.GetExeCtx(ctx)
|
||||
env = ternary.IFElse(execCtx.ExeCfg.Mode == vo.ExecuteModeRelease, vo.Online, vo.Draft)
|
||||
appID = execCtx.ExeCfg.AppID
|
||||
agentID = execCtx.ExeCfg.AgentID
|
||||
connectorID = execCtx.ExeCfg.ConnectorID
|
||||
userID = execCtx.ExeCfg.Operator
|
||||
version = execCtx.ExeCfg.Version
|
||||
)
|
||||
if agentID != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, query conversation list is not available"))
|
||||
}
|
||||
if appID == nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("query conversation list node, app id is required"))
|
||||
}
|
||||
|
||||
templates, err := workflow.GetRepository().ListConversationTemplate(ctx, env, &vo.ListConversationTemplatePolicy{
|
||||
AppID: *appID,
|
||||
Version: ptr.Of(version),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
templateIds := make([]int64, 0, len(templates))
|
||||
for _, template := range templates {
|
||||
templateIds = append(templateIds, template.TemplateID)
|
||||
}
|
||||
|
||||
staticConversations, err := workflow.GetRepository().MGetStaticConversation(ctx, env, userID, connectorID, templateIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
templateIDToConvID := slices.ToMap(staticConversations, func(conv *entity.StaticConversation) (int64, int64) {
|
||||
return conv.TemplateID, conv.ConversationID
|
||||
})
|
||||
|
||||
var conversationList []conversationInfo
|
||||
|
||||
for _, template := range templates {
|
||||
convID, ok := templateIDToConvID[template.TemplateID]
|
||||
if !ok {
|
||||
convID = 0
|
||||
}
|
||||
conversationList = append(conversationList, conversationInfo{
|
||||
conversationName: template.Name,
|
||||
conversationId: strconv.FormatInt(convID, 10),
|
||||
})
|
||||
}
|
||||
|
||||
dynamicConversations, err := workflow.GetRepository().ListDynamicConversation(ctx, env, &vo.ListConversationPolicy{
|
||||
ListConversationMeta: vo.ListConversationMeta{
|
||||
APPID: *appID,
|
||||
UserID: userID,
|
||||
ConnectorID: connectorID,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, conv := range dynamicConversations {
|
||||
conversationList = append(conversationList, conversationInfo{
|
||||
conversationName: conv.Name,
|
||||
conversationId: strconv.FormatInt(conv.ConversationID, 10),
|
||||
})
|
||||
}
|
||||
|
||||
resultList := make([]any, len(conversationList))
|
||||
for i, v := range conversationList {
|
||||
resultList[i] = map[string]any{
|
||||
"conversationName": v.conversationName,
|
||||
"conversationId": v.conversationId,
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"conversationList": resultList,
|
||||
}, nil
|
||||
|
||||
}
|
||||
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type ConversationHistoryConfig struct {
|
||||
Manager conversation.ConversationManager
|
||||
}
|
||||
|
||||
type ConversationHistory struct {
|
||||
cfg *ConversationHistoryConfig
|
||||
}
|
||||
|
||||
func NewConversationHistory(_ context.Context, cfg *ConversationHistoryConfig) (*ConversationHistory, error) {
|
||||
if cfg == nil {
|
||||
return nil, errors.New("config is required")
|
||||
}
|
||||
if cfg.Manager == nil {
|
||||
return nil, errors.New("manager is required")
|
||||
}
|
||||
return &ConversationHistory{
|
||||
cfg: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ch *ConversationHistory) HistoryMessages(ctx context.Context, input map[string]any) (map[string]any, error) {
|
||||
var (
|
||||
execCtx = execute.GetExeCtx(ctx)
|
||||
env = ternary.IFElse(execCtx.ExeCfg.Mode == vo.ExecuteModeRelease, vo.Online, vo.Draft)
|
||||
appID = execCtx.ExeCfg.AppID
|
||||
agentID = execCtx.ExeCfg.AgentID
|
||||
connectorID = execCtx.ExeCfg.ConnectorID
|
||||
userID = execCtx.ExeCfg.Operator
|
||||
version = execCtx.ExeCfg.Version
|
||||
)
|
||||
if agentID != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, query conversation list is not available"))
|
||||
}
|
||||
if appID == nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("query conversation list node, app id is required"))
|
||||
}
|
||||
|
||||
conversationName, ok := input["conversationName"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversation name is required"))
|
||||
}
|
||||
|
||||
rounds, ok := input["rounds"].(int64)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("rounds is required"))
|
||||
}
|
||||
|
||||
template, existed, err := wf.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
|
||||
AppID: appID,
|
||||
Name: ptr.Of(conversationName),
|
||||
Version: ptr.Of(version),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
var conversationID int64
|
||||
if existed {
|
||||
sts, existed, err := wf.GetRepository().GetStaticConversationByTemplateID(ctx, env, userID, connectorID, template.TemplateID)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
if existed {
|
||||
conversationID = sts.ConversationID
|
||||
}
|
||||
|
||||
} else {
|
||||
dyConversation, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
if existed {
|
||||
conversationID = dyConversation.ConversationID
|
||||
}
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return nil, vo.WrapError(errno.ErrConversationOfAppNotFound, fmt.Errorf("the conversation name does not exist: '%v'", conversationName))
|
||||
}
|
||||
|
||||
isChatFlow := execCtx.ExeCfg.WorkflowMode == workflow.WorkflowMode_ChatFlow
|
||||
if isChatFlow {
|
||||
rounds += 1
|
||||
}
|
||||
|
||||
runIDs, err := ch.cfg.Manager.GetLatestRunIDs(ctx, &conversation.GetLatestRunIDsRequest{
|
||||
ConversationID: conversationID,
|
||||
UserID: userID,
|
||||
AppID: *appID,
|
||||
Rounds: rounds,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
var messageList []any
|
||||
if len(runIDs) == 0 {
|
||||
return map[string]any{
|
||||
"messageList": messageList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if isChatFlow {
|
||||
if len(runIDs) == 1 {
|
||||
return map[string]any{
|
||||
"messageList": messageList,
|
||||
}, nil
|
||||
}
|
||||
runIDs = runIDs[1:] // chatflow needs to filter out this session
|
||||
}
|
||||
|
||||
response, err := ch.cfg.Manager.GetMessagesByRunIDs(ctx, &conversation.GetMessagesByRunIDsRequest{
|
||||
ConversationID: conversationID,
|
||||
RunIDs: runIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
for _, msg := range response.Messages {
|
||||
content, err := ConvertMessageToString(ctx, msg)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
messageList = append(messageList, map[string]any{
|
||||
"role": msg.Role,
|
||||
"content": content,
|
||||
})
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"messageList": messageList,
|
||||
}, nil
|
||||
}
|
||||
@ -19,27 +19,31 @@ package conversation
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type CreateConversationConfig struct {
|
||||
Creator conversation.ConversationManager
|
||||
Manager conversation.ConversationManager
|
||||
}
|
||||
|
||||
type CreateConversation struct {
|
||||
config *CreateConversationConfig
|
||||
}
|
||||
|
||||
func NewCreateConversation(ctx context.Context, cfg *CreateConversationConfig) (*CreateConversation, error) {
|
||||
func NewCreateConversation(_ context.Context, cfg *CreateConversationConfig) (*CreateConversation, error) {
|
||||
if cfg == nil {
|
||||
return nil, errors.New("config is required")
|
||||
}
|
||||
if cfg.Creator == nil {
|
||||
return nil, errors.New("creator is required")
|
||||
if cfg.Manager == nil {
|
||||
return nil, errors.New("manager is required")
|
||||
}
|
||||
return &CreateConversation{
|
||||
config: cfg,
|
||||
@ -47,16 +51,76 @@ func NewCreateConversation(ctx context.Context, cfg *CreateConversationConfig) (
|
||||
}
|
||||
|
||||
func (c *CreateConversation) Create(ctx context.Context, input map[string]any) (map[string]any, error) {
|
||||
name, ok := nodes.TakeMapValue(input, compose.FieldPath{"ConversationName"})
|
||||
if !ok {
|
||||
return nil, errors.New("input map should contains 'ConversationName' key ")
|
||||
|
||||
var (
|
||||
execCtx = execute.GetExeCtx(ctx)
|
||||
env = ternary.IFElse(execCtx.ExeCfg.Mode == vo.ExecuteModeRelease, vo.Online, vo.Draft)
|
||||
appID = execCtx.ExeCfg.AppID
|
||||
agentID = execCtx.ExeCfg.AgentID
|
||||
version = execCtx.ExeCfg.Version
|
||||
connectorID = execCtx.ExeCfg.ConnectorID
|
||||
userID = execCtx.ExeCfg.Operator
|
||||
conversationIDGenerator = workflow.ConversationIDGenerator(func(ctx context.Context, appID int64, userID, connectorID int64) (int64, error) {
|
||||
return c.config.Manager.CreateConversation(ctx, &conversation.CreateConversationRequest{
|
||||
AppID: appID,
|
||||
UserID: userID,
|
||||
ConnectorID: connectorID,
|
||||
})
|
||||
})
|
||||
)
|
||||
if agentID != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, create conversation is not available"))
|
||||
}
|
||||
response, err := c.config.Creator.CreateConversation(ctx, &conversation.CreateConversationRequest{
|
||||
Name: name.(string),
|
||||
|
||||
if appID == nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, errors.New("create conversation node, app id is required"))
|
||||
}
|
||||
|
||||
conversationName, ok := input["conversationName"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversation name is required"))
|
||||
}
|
||||
|
||||
template, existed, err := workflow.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
|
||||
AppID: appID,
|
||||
Name: ptr.Of(conversationName),
|
||||
Version: ptr.Of(version),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.Result, nil
|
||||
|
||||
if existed {
|
||||
cID, existed, err := workflow.GetRepository().GetOrCreateStaticConversation(ctx, env, conversationIDGenerator, &vo.CreateStaticConversation{
|
||||
AppID: ptr.From(appID),
|
||||
TemplateID: template.TemplateID,
|
||||
UserID: userID,
|
||||
ConnectorID: connectorID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{
|
||||
"isSuccess": true,
|
||||
"conversationId": cID,
|
||||
"isExisted": existed,
|
||||
}, nil
|
||||
}
|
||||
|
||||
cID, existed, err := workflow.GetRepository().GetOrCreateDynamicConversation(ctx, env, conversationIDGenerator, &vo.CreateDynamicConversation{
|
||||
AppID: ptr.From(appID),
|
||||
UserID: userID,
|
||||
ConnectorID: connectorID,
|
||||
Name: conversationName,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"isSuccess": true,
|
||||
"conversationId": cID,
|
||||
"isExisted": existed,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type CreateMessageConfig struct {
|
||||
Creator conversation.ConversationManager
|
||||
}
|
||||
type CreateMessage struct {
|
||||
config *CreateMessageConfig
|
||||
}
|
||||
|
||||
func NewCreateMessage(_ context.Context, cfg *CreateMessageConfig) (*CreateMessage, error) {
|
||||
if cfg == nil {
|
||||
return nil, errors.New("config is required")
|
||||
}
|
||||
if cfg.Creator == nil {
|
||||
return nil, errors.New("creator is required")
|
||||
}
|
||||
return &CreateMessage{
|
||||
config: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *CreateMessage) getConversationIDByName(ctx context.Context, env vo.Env, appID *int64, version, conversationName string, userID, connectorID int64) (int64, error) {
|
||||
template, isExist, err := workflow.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
|
||||
AppID: appID,
|
||||
Name: ptr.Of(conversationName),
|
||||
Version: ptr.Of(version),
|
||||
})
|
||||
if err != nil {
|
||||
return 0, vo.WrapError(errno.ErrConversationNodeInvalidOperation, err)
|
||||
}
|
||||
|
||||
conversationIDGenerator := workflow.ConversationIDGenerator(func(ctx context.Context, appID int64, userID, connectorID int64) (int64, error) {
|
||||
return c.config.Creator.CreateConversation(ctx, &conversation.CreateConversationRequest{
|
||||
AppID: appID,
|
||||
UserID: userID,
|
||||
ConnectorID: connectorID,
|
||||
})
|
||||
})
|
||||
|
||||
var conversationID int64
|
||||
if isExist {
|
||||
cID, _, err := workflow.GetRepository().GetOrCreateStaticConversation(ctx, env, conversationIDGenerator, &vo.CreateStaticConversation{
|
||||
AppID: ptr.From(appID),
|
||||
TemplateID: template.TemplateID,
|
||||
UserID: userID,
|
||||
ConnectorID: connectorID,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
conversationID = cID
|
||||
} else {
|
||||
dc, _, err := workflow.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if dc != nil {
|
||||
conversationID = dc.ConversationID
|
||||
}
|
||||
}
|
||||
return conversationID, nil
|
||||
}
|
||||
|
||||
func (c *CreateMessage) Create(ctx context.Context, input map[string]any) (map[string]any, error) {
|
||||
var (
|
||||
execCtx = execute.GetExeCtx(ctx)
|
||||
env = ternary.IFElse(execCtx.ExeCfg.Mode == vo.ExecuteModeRelease, vo.Online, vo.Draft)
|
||||
appID = execCtx.ExeCfg.AppID
|
||||
agentID = execCtx.ExeCfg.AgentID
|
||||
version = execCtx.ExeCfg.Version
|
||||
connectorID = execCtx.ExeCfg.ConnectorID
|
||||
userID = execCtx.ExeCfg.Operator
|
||||
)
|
||||
|
||||
conversationName, ok := input["conversationName"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversationName is required"))
|
||||
}
|
||||
|
||||
role, ok := input["role"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("role is required"))
|
||||
}
|
||||
if role != "user" && role != "assistant" {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, fmt.Errorf("role must be user or assistant"))
|
||||
}
|
||||
|
||||
content, ok := input["content"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodeInvalidOperation, errors.New("content is required"))
|
||||
}
|
||||
|
||||
var conversationID int64
|
||||
var err error
|
||||
var resolvedAppID int64
|
||||
if appID == nil {
|
||||
if conversationName != "Default" {
|
||||
return nil, vo.WrapError(errno.ErrOnlyDefaultConversationAllowInAgentScenario, errors.New("conversation node only allow in application"))
|
||||
}
|
||||
if agentID == nil || execCtx.ExeCfg.ConversationID == nil {
|
||||
return map[string]any{
|
||||
"isSuccess": false,
|
||||
"message": map[string]any{
|
||||
"messageId": "0",
|
||||
"role": role,
|
||||
"contentType": "text",
|
||||
"content": content,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
conversationID = *execCtx.ExeCfg.ConversationID
|
||||
resolvedAppID = *agentID
|
||||
} else {
|
||||
conversationID, err = c.getConversationIDByName(ctx, env, appID, version, conversationName, userID, connectorID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resolvedAppID = *appID
|
||||
}
|
||||
|
||||
if conversationID == 0 {
|
||||
return map[string]any{
|
||||
"isSuccess": false,
|
||||
"message": map[string]any{
|
||||
"messageId": "0",
|
||||
"role": role,
|
||||
"contentType": "text",
|
||||
"content": content,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
currentConversationID := execCtx.ExeCfg.ConversationID
|
||||
isCurrentConversation := currentConversationID != nil && *currentConversationID == conversationID
|
||||
var runID int64
|
||||
|
||||
if role == "user" {
|
||||
// For user messages, always create a new run and store the ID in the context.
|
||||
newRunID, err := workflow.GetRepository().GenID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if execCtx.ExeCfg.RoundID != nil {
|
||||
atomic.StoreInt64(execCtx.ExeCfg.RoundID, newRunID)
|
||||
}
|
||||
runID = newRunID
|
||||
} else if isCurrentConversation {
|
||||
// For assistant messages in the same conversation, reuse the runID from the context.
|
||||
if execCtx.ExeCfg.RoundID == nil {
|
||||
// This indicates an inconsistent state, as a user message should have set this.
|
||||
return map[string]any{
|
||||
"isSuccess": false,
|
||||
"message": map[string]any{
|
||||
"messageId": "0",
|
||||
"role": role,
|
||||
"contentType": "text",
|
||||
"content": content,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
runID = *execCtx.ExeCfg.RoundID
|
||||
} else {
|
||||
// For assistant messages in a different conversation or a new workflow run,
|
||||
// find the latest runID or create a new one as a fallback.
|
||||
runIDs, err := c.config.Creator.GetLatestRunIDs(ctx, &conversation.GetLatestRunIDsRequest{
|
||||
ConversationID: conversationID,
|
||||
UserID: userID,
|
||||
AppID: resolvedAppID,
|
||||
Rounds: 1,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(runIDs) > 0 && runIDs[0] != 0 {
|
||||
runID = runIDs[0]
|
||||
} else {
|
||||
newRunID, err := workflow.GetRepository().GenID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
runID = newRunID
|
||||
}
|
||||
}
|
||||
|
||||
mID, err := c.config.Creator.CreateMessage(ctx, &conversation.CreateMessageRequest{
|
||||
ConversationID: conversationID,
|
||||
Role: role,
|
||||
Content: content,
|
||||
ContentType: "text",
|
||||
UserID: userID,
|
||||
AppID: resolvedAppID,
|
||||
RunID: runID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create message: %w", err)
|
||||
}
|
||||
|
||||
messageOutput := map[string]any{
|
||||
"messageId": mID,
|
||||
"role": role,
|
||||
"contentType": "text",
|
||||
"content": content,
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"isSuccess": true,
|
||||
"message": messageOutput,
|
||||
}, nil
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type DeleteConversation struct {
|
||||
}
|
||||
|
||||
func NewDeleteConversation(_ context.Context) *DeleteConversation {
|
||||
return &DeleteConversation{}
|
||||
}
|
||||
|
||||
func (c *DeleteConversation) Delete(ctx context.Context, in map[string]any) (map[string]any, error) {
|
||||
|
||||
var (
|
||||
execCtx = execute.GetExeCtx(ctx)
|
||||
env = ternary.IFElse(execCtx.ExeCfg.Mode == vo.ExecuteModeRelease, vo.Online, vo.Draft)
|
||||
appID = execCtx.ExeCfg.AppID
|
||||
agentID = execCtx.ExeCfg.AgentID
|
||||
version = execCtx.ExeCfg.Version
|
||||
connectorID = execCtx.ExeCfg.ConnectorID
|
||||
userID = execCtx.ExeCfg.Operator
|
||||
)
|
||||
|
||||
if agentID != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, delete conversation is not available"))
|
||||
}
|
||||
|
||||
if appID == nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, errors.New("delete conversation node, app id is required"))
|
||||
}
|
||||
|
||||
cName, ok := in["conversationName"]
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversation name is required"))
|
||||
}
|
||||
|
||||
conversationName := cName.(string)
|
||||
|
||||
_, existed, err := wf.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
|
||||
AppID: appID,
|
||||
Name: ptr.Of(conversationName),
|
||||
Version: ptr.Of(version),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existed {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodeInvalidOperation, fmt.Errorf("only conversation created through nodes are allowed to be modified or deleted"))
|
||||
}
|
||||
|
||||
dyConversation, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return nil, vo.WrapError(errno.ErrConversationOfAppNotFound, fmt.Errorf("the conversation name does not exist: '%v'", conversationName))
|
||||
}
|
||||
|
||||
_, err = wf.GetRepository().DeleteDynamicConversation(ctx, env, dyConversation.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"isSuccess": true,
|
||||
}, nil
|
||||
}
|
||||
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type DeleteMessageConfig struct {
|
||||
Manager conversation.ConversationManager
|
||||
}
|
||||
|
||||
type DeleteMessage struct {
|
||||
config *DeleteMessageConfig
|
||||
}
|
||||
|
||||
func NewDeleteMessage(_ context.Context, cfg *DeleteMessageConfig) (*DeleteMessage, error) {
|
||||
if cfg == nil {
|
||||
return nil, errors.New("config is required")
|
||||
}
|
||||
if cfg.Manager == nil {
|
||||
return nil, errors.New("manager is required")
|
||||
}
|
||||
|
||||
return &DeleteMessage{
|
||||
config: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *DeleteMessage) Delete(ctx context.Context, input map[string]any) (map[string]any, error) {
|
||||
var (
|
||||
execCtx = execute.GetExeCtx(ctx)
|
||||
env = ternary.IFElse(execCtx.ExeCfg.Mode == vo.ExecuteModeRelease, vo.Online, vo.Draft)
|
||||
appID = execCtx.ExeCfg.AppID
|
||||
agentID = execCtx.ExeCfg.AgentID
|
||||
version = execCtx.ExeCfg.Version
|
||||
connectorID = execCtx.ExeCfg.ConnectorID
|
||||
userID = execCtx.ExeCfg.Operator
|
||||
|
||||
successMap = map[string]any{
|
||||
"isSuccess": true,
|
||||
}
|
||||
failedMap = map[string]any{
|
||||
"isSuccess": false,
|
||||
}
|
||||
)
|
||||
|
||||
conversationName, ok := input["conversationName"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversationName is required"))
|
||||
}
|
||||
messageStr, ok := input["messageId"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("messageId is required"))
|
||||
}
|
||||
messageID, err := strconv.ParseInt(messageStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, err)
|
||||
}
|
||||
|
||||
if appID == nil {
|
||||
if conversationName != "Default" {
|
||||
return nil, vo.WrapError(errno.ErrOnlyDefaultConversationAllowInAgentScenario, fmt.Errorf("only default conversation allow in agent scenario"))
|
||||
}
|
||||
|
||||
if agentID == nil || execCtx.ExeCfg.ConversationID == nil {
|
||||
return failedMap, nil
|
||||
}
|
||||
|
||||
err = c.config.Manager.DeleteMessage(ctx, &conversation.DeleteMessageRequest{ConversationID: *execCtx.ExeCfg.ConversationID, MessageID: messageID})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
return successMap, nil
|
||||
}
|
||||
|
||||
t, existed, err := wf.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
|
||||
AppID: appID,
|
||||
Name: ptr.Of(conversationName),
|
||||
Version: ptr.Of(version),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
if existed {
|
||||
sts, existed, err := wf.GetRepository().GetStaticConversationByTemplateID(ctx, env, userID, connectorID, t.TemplateID)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return failedMap, nil
|
||||
}
|
||||
|
||||
err = c.config.Manager.DeleteMessage(ctx, &conversation.DeleteMessageRequest{ConversationID: sts.ConversationID, MessageID: messageID})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
return successMap, nil
|
||||
|
||||
} else {
|
||||
dyConversation, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return failedMap, nil
|
||||
}
|
||||
|
||||
err = c.config.Manager.DeleteMessage(ctx, &conversation.DeleteMessageRequest{ConversationID: dyConversation.ConversationID, MessageID: messageID})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
return successMap, nil
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type EditMessageConfig struct {
|
||||
Manager conversation.ConversationManager
|
||||
}
|
||||
|
||||
type EditMessage struct {
|
||||
config *EditMessageConfig
|
||||
}
|
||||
|
||||
func NewEditMessage(_ context.Context, cfg *EditMessageConfig) (*EditMessage, error) {
|
||||
if cfg == nil {
|
||||
return nil, errors.New("config is required")
|
||||
}
|
||||
if cfg.Manager == nil {
|
||||
return nil, errors.New("clearer is required")
|
||||
}
|
||||
|
||||
return &EditMessage{
|
||||
config: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *EditMessage) Edit(ctx context.Context, input map[string]any) (map[string]any, error) {
|
||||
var (
|
||||
execCtx = execute.GetExeCtx(ctx)
|
||||
env = ternary.IFElse(execCtx.ExeCfg.Mode == vo.ExecuteModeRelease, vo.Online, vo.Draft)
|
||||
appID = execCtx.ExeCfg.AppID
|
||||
agentID = execCtx.ExeCfg.AgentID
|
||||
version = execCtx.ExeCfg.Version
|
||||
connectorID = execCtx.ExeCfg.ConnectorID
|
||||
userID = execCtx.ExeCfg.Operator
|
||||
|
||||
successMap = map[string]any{
|
||||
"isSuccess": true,
|
||||
}
|
||||
failedMap = map[string]any{
|
||||
"isSuccess": false,
|
||||
}
|
||||
)
|
||||
|
||||
conversationName, ok := input["conversationName"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversationName is required"))
|
||||
}
|
||||
|
||||
messageStr, ok := input["messageId"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("messageId is required"))
|
||||
}
|
||||
|
||||
messageID, err := strconv.ParseInt(messageStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
newContent, ok := input["newContent"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("newContent is required"))
|
||||
}
|
||||
|
||||
if appID == nil {
|
||||
if conversationName != "Default" {
|
||||
return nil, vo.WrapError(errno.ErrOnlyDefaultConversationAllowInAgentScenario, fmt.Errorf("only default conversation allow in agent scenario"))
|
||||
}
|
||||
|
||||
if agentID == nil || execCtx.ExeCfg.ConversationID == nil {
|
||||
return failedMap, nil
|
||||
}
|
||||
|
||||
err = e.config.Manager.EditMessage(ctx, &conversation.EditMessageRequest{ConversationID: *execCtx.ExeCfg.ConversationID, MessageID: messageID, Content: newContent})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
return successMap, err
|
||||
}
|
||||
|
||||
t, existed, err := wf.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
|
||||
AppID: appID,
|
||||
Name: ptr.Of(conversationName),
|
||||
Version: ptr.Of(version),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
if existed {
|
||||
sts, existed, err := wf.GetRepository().GetStaticConversationByTemplateID(ctx, env, userID, connectorID, t.TemplateID)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return failedMap, nil
|
||||
}
|
||||
|
||||
err = e.config.Manager.DeleteMessage(ctx, &conversation.DeleteMessageRequest{ConversationID: sts.ConversationID, MessageID: messageID})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
return successMap, nil
|
||||
|
||||
} else {
|
||||
dyConversation, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return failedMap, nil
|
||||
}
|
||||
|
||||
err = e.config.Manager.EditMessage(ctx, &conversation.EditMessageRequest{ConversationID: dyConversation.ConversationID, MessageID: messageID, Content: newContent})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, err)
|
||||
}
|
||||
|
||||
return successMap, nil
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -18,13 +18,17 @@ package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type MessageListConfig struct {
|
||||
@ -34,14 +38,7 @@ type MessageList struct {
|
||||
config *MessageListConfig
|
||||
}
|
||||
|
||||
type Param struct {
|
||||
ConversationName string
|
||||
Limit *int
|
||||
BeforeID *string
|
||||
AfterID *string
|
||||
}
|
||||
|
||||
func NewMessageList(ctx context.Context, cfg *MessageListConfig) (*MessageList, error) {
|
||||
func NewMessageList(_ context.Context, cfg *MessageListConfig) (*MessageList, error) {
|
||||
if cfg == nil {
|
||||
return nil, errors.New("config is required")
|
||||
}
|
||||
@ -56,53 +53,155 @@ func NewMessageList(ctx context.Context, cfg *MessageListConfig) (*MessageList,
|
||||
|
||||
}
|
||||
|
||||
func (m *MessageList) List(ctx context.Context, input map[string]any) (map[string]any, error) {
|
||||
param := &Param{}
|
||||
name, ok := nodes.TakeMapValue(input, compose.FieldPath{"ConversationName"})
|
||||
if !ok {
|
||||
return nil, errors.New("ConversationName is required")
|
||||
}
|
||||
param.ConversationName = name.(string)
|
||||
limit, ok := nodes.TakeMapValue(input, compose.FieldPath{"Limit"})
|
||||
if ok {
|
||||
limit := limit.(int)
|
||||
param.Limit = &limit
|
||||
}
|
||||
beforeID, ok := nodes.TakeMapValue(input, compose.FieldPath{"BeforeID"})
|
||||
if ok {
|
||||
beforeID := beforeID.(string)
|
||||
param.BeforeID = &beforeID
|
||||
}
|
||||
afterID, ok := nodes.TakeMapValue(input, compose.FieldPath{"AfterID"})
|
||||
if ok {
|
||||
afterID := afterID.(string)
|
||||
param.BeforeID = &afterID
|
||||
}
|
||||
r, err := m.config.Lister.MessageList(ctx, &conversation.ListMessageRequest{
|
||||
ConversationName: param.ConversationName,
|
||||
Limit: param.Limit,
|
||||
BeforeID: param.BeforeID,
|
||||
AfterID: param.AfterID,
|
||||
func (m *MessageList) getConversationIDByName(ctx context.Context, env vo.Env, appID *int64, version, conversationName string, userID, connectorID int64) (int64, error) {
|
||||
template, isExist, err := workflow.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
|
||||
AppID: appID,
|
||||
Name: ptr.Of(conversationName),
|
||||
Version: ptr.Of(version),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return 0, vo.WrapError(errno.ErrConversationNodeInvalidOperation, err)
|
||||
}
|
||||
|
||||
var conversationID int64
|
||||
if isExist {
|
||||
sc, _, err := workflow.GetRepository().GetStaticConversationByTemplateID(ctx, env, userID, connectorID, template.TemplateID)
|
||||
if err != nil {
|
||||
return 0, vo.WrapError(errno.ErrConversationNodeInvalidOperation, err)
|
||||
}
|
||||
if sc != nil {
|
||||
conversationID = sc.ConversationID
|
||||
}
|
||||
} else {
|
||||
dc, _, err := workflow.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
|
||||
if err != nil {
|
||||
return 0, vo.WrapError(errno.ErrConversationNodeInvalidOperation, err)
|
||||
}
|
||||
if dc != nil {
|
||||
conversationID = dc.ConversationID
|
||||
}
|
||||
}
|
||||
|
||||
return conversationID, nil
|
||||
}
|
||||
|
||||
func (m *MessageList) List(ctx context.Context, input map[string]any) (map[string]any, error) {
|
||||
var (
|
||||
execCtx = execute.GetExeCtx(ctx)
|
||||
env = ternary.IFElse(execCtx.ExeCfg.Mode == vo.ExecuteModeRelease, vo.Online, vo.Draft)
|
||||
appID = execCtx.ExeCfg.AppID
|
||||
agentID = execCtx.ExeCfg.AgentID
|
||||
version = execCtx.ExeCfg.Version
|
||||
connectorID = execCtx.ExeCfg.ConnectorID
|
||||
userID = execCtx.ExeCfg.Operator
|
||||
)
|
||||
|
||||
conversationName, ok := input["conversationName"].(string)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodeInvalidOperation, errors.New("ConversationName is required"))
|
||||
}
|
||||
|
||||
var conversationID int64
|
||||
var err error
|
||||
var resolvedAppID int64
|
||||
if appID == nil {
|
||||
if conversationName != "Default" {
|
||||
return nil, vo.WrapError(errno.ErrOnlyDefaultConversationAllowInAgentScenario, errors.New("conversation node only allow in application"))
|
||||
}
|
||||
if agentID == nil || execCtx.ExeCfg.ConversationID == nil {
|
||||
return map[string]any{
|
||||
"messageList": []any{},
|
||||
"firstId": "0",
|
||||
"lastId": "0",
|
||||
"hasMore": false,
|
||||
}, nil
|
||||
}
|
||||
conversationID = *execCtx.ExeCfg.ConversationID
|
||||
resolvedAppID = *agentID
|
||||
} else {
|
||||
conversationID, err = m.getConversationIDByName(ctx, env, appID, version, conversationName, userID, connectorID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resolvedAppID = *appID
|
||||
}
|
||||
|
||||
req := &conversation.MessageListRequest{
|
||||
UserID: userID,
|
||||
AppID: resolvedAppID,
|
||||
ConversationID: conversationID,
|
||||
}
|
||||
|
||||
if req.ConversationID == 0 {
|
||||
return map[string]any{
|
||||
"messageList": []any{},
|
||||
"firstId": "0",
|
||||
"lastId": "0",
|
||||
"hasMore": false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
limit, ok := input["Limit"].(int64)
|
||||
if ok {
|
||||
if limit > 0 && limit <= 50 {
|
||||
req.Limit = limit
|
||||
} else {
|
||||
req.Limit = 50
|
||||
}
|
||||
} else {
|
||||
req.Limit = 50
|
||||
}
|
||||
beforeID, ok := input["beforeId"].(string)
|
||||
if ok {
|
||||
|
||||
req.BeforeID = &beforeID
|
||||
}
|
||||
afterID, ok := input["afterId"].(string)
|
||||
if ok {
|
||||
|
||||
req.AfterID = &afterID
|
||||
}
|
||||
|
||||
if beforeID != "" && afterID != "" {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, fmt.Errorf("BeforeID and AfterID cannot be set at the same time"))
|
||||
}
|
||||
|
||||
ml, err := m.config.Lister.MessageList(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]any)
|
||||
objects := make([]any, 0, len(r.Messages))
|
||||
for _, msg := range r.Messages {
|
||||
object := make(map[string]any)
|
||||
bs, _ := json.Marshal(msg)
|
||||
err := json.Unmarshal(bs, &object)
|
||||
var messageList []any
|
||||
for _, msg := range ml.Messages {
|
||||
content, err := ConvertMessageToString(ctx, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
objects = append(objects, object)
|
||||
messageList = append(messageList, map[string]any{
|
||||
"messageId": strconv.FormatInt(msg.ID, 10),
|
||||
"role": msg.Role,
|
||||
"contentType": msg.ContentType,
|
||||
"content": content,
|
||||
})
|
||||
}
|
||||
|
||||
result["messageList"] = objects
|
||||
result["firstId"] = r.FirstID
|
||||
result["hasMore"] = r.HasMore
|
||||
return result, nil
|
||||
// TODO: After the List interface is updated, the firstId and lastId from the response can be returned directly without extra processing
|
||||
var firstId, lastId any = "0", "0"
|
||||
if len(messageList) > 0 {
|
||||
if firstMsg, ok := messageList[0].(map[string]any); ok {
|
||||
firstId = firstMsg["messageId"]
|
||||
}
|
||||
if lastMsg, ok := messageList[len(messageList)-1].(map[string]any); ok {
|
||||
lastId = lastMsg["messageId"]
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"messageList": messageList,
|
||||
"firstId": firstId,
|
||||
"lastId": lastId,
|
||||
"hasMore": ml.HasMore,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type UpdateConversation struct {
|
||||
}
|
||||
|
||||
func NewUpdateConversation(_ context.Context) *UpdateConversation {
|
||||
return &UpdateConversation{}
|
||||
}
|
||||
|
||||
func (c *UpdateConversation) Update(ctx context.Context, in map[string]any) (map[string]any, error) {
|
||||
|
||||
var (
|
||||
execCtx = execute.GetExeCtx(ctx)
|
||||
env = ternary.IFElse(execCtx.ExeCfg.Mode == vo.ExecuteModeRelease, vo.Online, vo.Draft)
|
||||
appID = execCtx.ExeCfg.AppID
|
||||
agentID = execCtx.ExeCfg.AgentID
|
||||
version = execCtx.ExeCfg.Version
|
||||
connectorID = execCtx.ExeCfg.ConnectorID
|
||||
userID = execCtx.ExeCfg.Operator
|
||||
)
|
||||
cName, ok := in["conversationName"]
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversation name is required"))
|
||||
}
|
||||
|
||||
conversationName := cName.(string)
|
||||
|
||||
ncName, ok := in["newConversationName"]
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("new conversationName name is required"))
|
||||
}
|
||||
|
||||
newConversationName := ncName.(string)
|
||||
|
||||
if agentID != nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, update conversation is not available"))
|
||||
}
|
||||
|
||||
if appID == nil {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, errors.New("conversation update node, app id is required"))
|
||||
}
|
||||
|
||||
_, existed, err := wf.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
|
||||
AppID: appID,
|
||||
Name: ptr.Of(conversationName),
|
||||
Version: ptr.Of(version),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existed {
|
||||
return nil, vo.WrapError(errno.ErrConversationNodeInvalidOperation, fmt.Errorf("only conversation created through nodes are allowed to be modified or deleted"))
|
||||
}
|
||||
|
||||
conversation, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return map[string]any{
|
||||
"conversationId": "0",
|
||||
"isSuccess": false,
|
||||
"isExisted": false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
ncConversation, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, newConversationName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existed {
|
||||
return map[string]any{
|
||||
"conversationId": strconv.FormatInt(ncConversation.ConversationID, 10),
|
||||
"isSuccess": false,
|
||||
"isExisted": true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
err = wf.GetRepository().UpdateDynamicConversationNameByID(ctx, env, conversation.ID, newConversationName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"conversationId": strconv.FormatInt(conversation.ConversationID, 10),
|
||||
"isSuccess": true,
|
||||
"isExisted": false,
|
||||
}, nil
|
||||
|
||||
}
|
||||
@ -29,17 +29,25 @@ import (
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/spf13/cast"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
nodesconversation "github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Intents []string
|
||||
SystemPrompt string
|
||||
IsFastMode bool
|
||||
ChatModel model.BaseChatModel
|
||||
Intents []string
|
||||
SystemPrompt string
|
||||
IsFastMode bool
|
||||
ChatModel model.BaseChatModel
|
||||
ChatHistorySetting *vo.ChatHistorySetting
|
||||
}
|
||||
|
||||
type contextKey string
|
||||
|
||||
const chatHistoryKey contextKey = "chatHistory"
|
||||
|
||||
const SystemIntentPrompt = `
|
||||
# Role
|
||||
You are an intention classification expert, good at being able to judge which classification the user's input belongs to.
|
||||
@ -125,7 +133,7 @@ func NewIntentDetector(ctx context.Context, cfg *Config) (*IntentDetector, error
|
||||
&schema.Message{Content: sptTemplate, Role: schema.System},
|
||||
&schema.Message{Content: "{{query}}", Role: schema.User})
|
||||
|
||||
r, err := chain.AppendChatTemplate(prompts).AppendChatModel(cfg.ChatModel).Compile(ctx)
|
||||
r, err := chain.AppendChatTemplate(newHistoryChatTemplate(prompts, cfg)).AppendChatModel(cfg.ChatModel).Compile(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -210,3 +218,24 @@ func toIntentString(its []string) string {
|
||||
itsBytes, _ := json.Marshal(vs)
|
||||
return string(itsBytes)
|
||||
}
|
||||
|
||||
func (id *IntentDetector) ToCallbackInput(ctx context.Context, in map[string]any) (map[string]any, error) {
|
||||
if id.config.ChatHistorySetting == nil || !id.config.ChatHistorySetting.EnableChatHistory {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
historyMessages, err := nodesconversation.GetConversationHistoryFromCtx(ctx, id.config.ChatHistorySetting.ChatHistoryRound)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "failed to get conversation history: %v", err)
|
||||
return in, nil
|
||||
}
|
||||
if historyMessages == nil {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
ret := map[string]any{
|
||||
"chatHistory": historyMessages,
|
||||
"query": in["query"],
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
101
backend/domain/workflow/internal/nodes/intentdetector/prompt.go
Normal file
101
backend/domain/workflow/internal/nodes/intentdetector/prompt.go
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package intentdetector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudwego/eino/components/prompt"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
oceanworkflow "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
nodesconversation "github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
)
|
||||
|
||||
type historyChatTemplate struct {
|
||||
basePrompt prompt.ChatTemplate
|
||||
cfg *Config
|
||||
}
|
||||
|
||||
func newHistoryChatTemplate(basePrompt prompt.ChatTemplate, cfg *Config) prompt.ChatTemplate {
|
||||
return &historyChatTemplate{
|
||||
basePrompt: basePrompt,
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *historyChatTemplate) Format(ctx context.Context, vs map[string]any, opts ...prompt.Option) ([]*schema.Message, error) {
|
||||
baseMessages, err := t.basePrompt.Format(ctx, vs, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to format base prompt: %w", err)
|
||||
}
|
||||
if len(baseMessages) == 0 {
|
||||
return nil, fmt.Errorf("base prompt returned no messages")
|
||||
}
|
||||
|
||||
if t.cfg.ChatHistorySetting == nil || !t.cfg.ChatHistorySetting.EnableChatHistory {
|
||||
return baseMessages, nil
|
||||
}
|
||||
|
||||
exeCtx := execute.GetExeCtx(ctx)
|
||||
if exeCtx == nil {
|
||||
logs.CtxWarnf(ctx, "execute context is nil, skipping chat history")
|
||||
return baseMessages, nil
|
||||
}
|
||||
|
||||
if exeCtx.ExeCfg.WorkflowMode != oceanworkflow.WorkflowMode_ChatFlow {
|
||||
return baseMessages, nil
|
||||
}
|
||||
|
||||
historyFromCtx, ok := ctxcache.Get[[]*conversation.Message](ctx, chatHistoryKey)
|
||||
var messages []*conversation.Message
|
||||
if ok {
|
||||
messages = historyFromCtx
|
||||
}
|
||||
|
||||
if len(messages) == 0 {
|
||||
logs.CtxWarnf(ctx, "conversation history is empty")
|
||||
return baseMessages, nil
|
||||
}
|
||||
|
||||
historyMessages := make([]*schema.Message, 0, len(messages))
|
||||
for _, msg := range messages {
|
||||
schemaMsg, err := nodesconversation.ConvertMessageToSchema(ctx, msg)
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "failed to convert history message, skipping: %v", err)
|
||||
continue
|
||||
}
|
||||
historyMessages = append(historyMessages, schemaMsg)
|
||||
}
|
||||
|
||||
if len(historyMessages) == 0 {
|
||||
return baseMessages, nil
|
||||
}
|
||||
|
||||
finalMessages := make([]*schema.Message, 0, len(baseMessages)+len(historyMessages))
|
||||
finalMessages = append(finalMessages, baseMessages[0]) // System prompt
|
||||
finalMessages = append(finalMessages, historyMessages...)
|
||||
if len(baseMessages) > 1 {
|
||||
finalMessages = append(finalMessages, baseMessages[1:]...) // User prompt and any others
|
||||
}
|
||||
|
||||
return finalMessages, nil
|
||||
}
|
||||
@ -20,16 +20,29 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
oceanworkflow "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/knowledge"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
nodesconversation "github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
)
|
||||
|
||||
const outputList = "outputList"
|
||||
|
||||
type contextKey string
|
||||
|
||||
const chatHistoryKey contextKey = "chatHistory"
|
||||
|
||||
type RetrieveConfig struct {
|
||||
KnowledgeIDs []int64
|
||||
RetrievalStrategy *knowledge.RetrievalStrategy
|
||||
Retriever knowledge.KnowledgeOperator
|
||||
KnowledgeIDs []int64
|
||||
RetrievalStrategy *knowledge.RetrievalStrategy
|
||||
Retriever knowledge.KnowledgeOperator
|
||||
ChatHistorySetting *vo.ChatHistorySetting
|
||||
}
|
||||
|
||||
type KnowledgeRetrieve struct {
|
||||
@ -69,6 +82,7 @@ func (kr *KnowledgeRetrieve) Retrieve(ctx context.Context, input map[string]any)
|
||||
Query: query,
|
||||
KnowledgeIDs: kr.config.KnowledgeIDs,
|
||||
RetrievalStrategy: kr.config.RetrievalStrategy,
|
||||
ChatHistory: kr.GetChatHistoryOrNil(ctx, kr.config),
|
||||
}
|
||||
|
||||
response, err := kr.config.Retriever.Retrieve(ctx, req)
|
||||
@ -85,3 +99,58 @@ func (kr *KnowledgeRetrieve) Retrieve(ctx context.Context, input map[string]any)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (kr *KnowledgeRetrieve) GetChatHistoryOrNil(ctx context.Context, cfg *RetrieveConfig) []*schema.Message {
|
||||
if cfg.ChatHistorySetting == nil || !cfg.ChatHistorySetting.EnableChatHistory {
|
||||
return nil
|
||||
}
|
||||
|
||||
exeCtx := execute.GetExeCtx(ctx)
|
||||
if exeCtx == nil {
|
||||
logs.CtxWarnf(ctx, "execute context is nil, skipping chat history")
|
||||
return nil
|
||||
}
|
||||
if exeCtx.ExeCfg.WorkflowMode != oceanworkflow.WorkflowMode_ChatFlow {
|
||||
return nil
|
||||
}
|
||||
|
||||
historyFromCtx, ok := ctxcache.Get[[]*conversation.Message](ctx, chatHistoryKey)
|
||||
var messages []*conversation.Message
|
||||
if ok {
|
||||
messages = historyFromCtx
|
||||
}
|
||||
|
||||
if len(messages) == 0 {
|
||||
logs.CtxWarnf(ctx, "conversation history is empty")
|
||||
return nil
|
||||
}
|
||||
|
||||
historyMessages := make([]*schema.Message, 0, len(messages))
|
||||
for _, msg := range messages {
|
||||
schemaMsg, err := nodesconversation.ConvertMessageToSchema(ctx, msg)
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "failed to convert history message, skipping: %v", err)
|
||||
continue
|
||||
}
|
||||
historyMessages = append(historyMessages, schemaMsg)
|
||||
}
|
||||
return historyMessages
|
||||
}
|
||||
|
||||
func (kr *KnowledgeRetrieve) ToCallbackInput(ctx context.Context, in map[string]any) (map[string]any, error) {
|
||||
if kr.config.ChatHistorySetting == nil || !kr.config.ChatHistorySetting.EnableChatHistory {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
messageList, err := nodesconversation.GetConversationHistoryFromCtx(ctx, kr.config.ChatHistorySetting.ChatHistoryRound)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "failed to get conversation history: %v", err)
|
||||
return in, nil
|
||||
}
|
||||
|
||||
ret := map[string]any{
|
||||
"chatHistory": messageList,
|
||||
"Query": in["Query"],
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
nodesconversation "github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
@ -50,6 +51,10 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
const chatHistoryKey contextKey = "chatHistory"
|
||||
|
||||
type Format int
|
||||
|
||||
const (
|
||||
@ -168,15 +173,17 @@ type Config struct {
|
||||
ToolsReturnDirectly map[string]bool
|
||||
KnowledgeRecallConfig *KnowledgeRecallConfig
|
||||
FullSources map[string]*nodes.SourceInfo
|
||||
ChatHistorySetting *vo.ChatHistorySetting
|
||||
}
|
||||
|
||||
type LLM struct {
|
||||
r compose.Runnable[map[string]any, map[string]any]
|
||||
outputFormat Format
|
||||
outputFields map[string]*vo.TypeInfo
|
||||
canStream bool
|
||||
requireCheckpoint bool
|
||||
fullSources map[string]*nodes.SourceInfo
|
||||
r compose.Runnable[map[string]any, map[string]any]
|
||||
outputFormat Format
|
||||
outputFields map[string]*vo.TypeInfo
|
||||
canStream bool
|
||||
requireCheckpoint bool
|
||||
fullSources map[string]*nodes.SourceInfo
|
||||
ChatHistorySetting *vo.ChatHistorySetting
|
||||
}
|
||||
|
||||
const (
|
||||
@ -313,8 +320,9 @@ func New(ctx context.Context, cfg *Config) (*LLM, error) {
|
||||
sp := newPromptTpl(schema.System, cfg.SystemPrompt, inputs, nil)
|
||||
up := newPromptTpl(schema.User, userPrompt, inputs, []string{knowledgeUserPromptTemplateKey})
|
||||
template := newPrompts(sp, up, cfg.ChatModel)
|
||||
templateWithChatHistory := newPromptsWithChatHistory(template, cfg.ChatHistorySetting)
|
||||
|
||||
_ = g.AddChatTemplateNode(templateNodeKey, template,
|
||||
_ = g.AddChatTemplateNode(templateNodeKey, templateWithChatHistory,
|
||||
compose.WithStatePreHandler(func(ctx context.Context, in map[string]any, state llmState) (map[string]any, error) {
|
||||
for k, v := range state {
|
||||
in[k] = v
|
||||
@ -327,7 +335,9 @@ func New(ctx context.Context, cfg *Config) (*LLM, error) {
|
||||
sp := newPromptTpl(schema.System, cfg.SystemPrompt, cfg.InputFields, nil)
|
||||
up := newPromptTpl(schema.User, userPrompt, cfg.InputFields, nil)
|
||||
template := newPrompts(sp, up, cfg.ChatModel)
|
||||
_ = g.AddChatTemplateNode(templateNodeKey, template)
|
||||
templateWithChatHistory := newPromptsWithChatHistory(template, cfg.ChatHistorySetting)
|
||||
|
||||
_ = g.AddChatTemplateNode(templateNodeKey, templateWithChatHistory)
|
||||
|
||||
_ = g.AddEdge(compose.START, templateNodeKey)
|
||||
}
|
||||
@ -471,11 +481,12 @@ func New(ctx context.Context, cfg *Config) (*LLM, error) {
|
||||
}
|
||||
|
||||
llm := &LLM{
|
||||
r: r,
|
||||
outputFormat: format,
|
||||
canStream: canStream,
|
||||
requireCheckpoint: requireCheckpoint,
|
||||
fullSources: cfg.FullSources,
|
||||
r: r,
|
||||
outputFormat: format,
|
||||
canStream: canStream,
|
||||
requireCheckpoint: requireCheckpoint,
|
||||
fullSources: cfg.FullSources,
|
||||
ChatHistorySetting: cfg.ChatHistorySetting,
|
||||
}
|
||||
|
||||
return llm, nil
|
||||
@ -813,6 +824,26 @@ type ToolInterruptEventStore interface {
|
||||
ResumeToolInterruptEvent(llmNodeKey vo.NodeKey, toolCallID string) (string, error)
|
||||
}
|
||||
|
||||
func (l *LLM) ToCallbackInput(ctx context.Context, input map[string]any) (map[string]any, error) {
|
||||
if l.ChatHistorySetting == nil || !l.ChatHistorySetting.EnableChatHistory {
|
||||
return input, nil
|
||||
}
|
||||
|
||||
messageList, err := nodesconversation.GetConversationHistoryFromCtx(ctx, l.ChatHistorySetting.ChatHistoryRound)
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "failed to get conversation history: %v", err)
|
||||
return input, nil
|
||||
}
|
||||
|
||||
ret := map[string]any{
|
||||
"chatHistory": messageList,
|
||||
}
|
||||
for k, v := range input {
|
||||
ret[k] = v
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (l *LLM) ToCallbackOutput(ctx context.Context, output map[string]any) (*nodes.StructuredCallbackOutput, error) {
|
||||
c := execute.GetExeCtx(ctx)
|
||||
if c == nil {
|
||||
|
||||
@ -23,11 +23,15 @@ import (
|
||||
"github.com/cloudwego/eino/components/prompt"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
oceanworkflow "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
nodesconversation "github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/modelmgr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
|
||||
)
|
||||
|
||||
@ -37,6 +41,11 @@ type prompts struct {
|
||||
mwi ModelWithInfo
|
||||
}
|
||||
|
||||
type promptsWithChatHistory struct {
|
||||
prompts *prompts
|
||||
cfg *vo.ChatHistorySetting
|
||||
}
|
||||
|
||||
type promptTpl struct {
|
||||
role schema.RoleType
|
||||
tpl string
|
||||
@ -106,6 +115,13 @@ func newPrompts(sp, up *promptTpl, model ModelWithInfo) *prompts {
|
||||
}
|
||||
}
|
||||
|
||||
func newPromptsWithChatHistory(prompts *prompts, cfg *vo.ChatHistorySetting) *promptsWithChatHistory {
|
||||
return &promptsWithChatHistory{
|
||||
prompts: prompts,
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func (pl *promptTpl) render(ctx context.Context, vs map[string]any,
|
||||
sources map[string]*nodes.SourceInfo,
|
||||
supportedModals map[modelmgr.Modal]bool,
|
||||
@ -287,3 +303,59 @@ func (p *prompts) Format(ctx context.Context, vs map[string]any, _ ...prompt.Opt
|
||||
|
||||
return []*schema.Message{systemMsg, userMsg}, nil
|
||||
}
|
||||
|
||||
func (p *promptsWithChatHistory) Format(ctx context.Context, vs map[string]any, _ ...prompt.Option) (
|
||||
[]*schema.Message, error) {
|
||||
baseMessages, err := p.prompts.Format(ctx, vs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.cfg == nil || !p.cfg.EnableChatHistory {
|
||||
return baseMessages, nil
|
||||
}
|
||||
|
||||
exeCtx := execute.GetExeCtx(ctx)
|
||||
if exeCtx == nil {
|
||||
logs.CtxWarnf(ctx, "execute context is nil, skipping chat history")
|
||||
return baseMessages, nil
|
||||
}
|
||||
|
||||
if exeCtx.ExeCfg.WorkflowMode != oceanworkflow.WorkflowMode_ChatFlow {
|
||||
return baseMessages, nil
|
||||
}
|
||||
|
||||
historyFromCtx, ok := ctxcache.Get[[]*conversation.Message](ctx, chatHistoryKey)
|
||||
var messages []*conversation.Message
|
||||
if ok {
|
||||
messages = historyFromCtx
|
||||
}
|
||||
|
||||
if len(messages) == 0 {
|
||||
logs.CtxWarnf(ctx, "conversation history is empty")
|
||||
return baseMessages, nil
|
||||
}
|
||||
|
||||
historyMessages := make([]*schema.Message, 0, len(messages))
|
||||
for _, msg := range messages {
|
||||
schemaMsg, err := nodesconversation.ConvertMessageToSchema(ctx, msg)
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "failed to convert history message, skipping: %v", err)
|
||||
continue
|
||||
}
|
||||
historyMessages = append(historyMessages, schemaMsg)
|
||||
}
|
||||
|
||||
if len(historyMessages) == 0 {
|
||||
return baseMessages, nil
|
||||
}
|
||||
|
||||
finalMessages := make([]*schema.Message, 0, len(baseMessages)+len(historyMessages))
|
||||
if len(baseMessages) > 0 && baseMessages[0].Role == schema.System {
|
||||
finalMessages = append(finalMessages, baseMessages[0])
|
||||
baseMessages = baseMessages[1:]
|
||||
}
|
||||
finalMessages = append(finalMessages, historyMessages...)
|
||||
finalMessages = append(finalMessages, baseMessages...)
|
||||
|
||||
return finalMessages, nil
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user