feat(workflow): add unit tests for message-related nodes (#1889)
This commit is contained in:
@ -43,16 +43,17 @@ import (
|
||||
"github.com/cloudwego/hertz/pkg/common/ut"
|
||||
"github.com/cloudwego/hertz/pkg/protocol"
|
||||
"github.com/cloudwego/hertz/pkg/protocol/sse"
|
||||
message0 "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/config"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/knowledge"
|
||||
modelknowledge "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/knowledge"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/modelmgr"
|
||||
plugin2 "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
pluginmodel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
@ -66,10 +67,16 @@ import (
|
||||
appplugin "github.com/coze-dev/coze-studio/backend/application/plugin"
|
||||
"github.com/coze-dev/coze-studio/backend/application/user"
|
||||
appworkflow "github.com/coze-dev/coze-studio/backend/application/workflow"
|
||||
crossagentrun "github.com/coze-dev/coze-studio/backend/crossdomain/contract/agentrun"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/agentrun/agentrunmock"
|
||||
crossconversation "github.com/coze-dev/coze-studio/backend/crossdomain/contract/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/conversation/conversationmock"
|
||||
crossdatabase "github.com/coze-dev/coze-studio/backend/crossdomain/contract/database"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/database/databasemock"
|
||||
crossknowledge "github.com/coze-dev/coze-studio/backend/crossdomain/contract/knowledge"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/knowledge/knowledgemock"
|
||||
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/message/messagemock"
|
||||
crossmodelmgr "github.com/coze-dev/coze-studio/backend/crossdomain/contract/modelmgr"
|
||||
mockmodel "github.com/coze-dev/coze-studio/backend/crossdomain/contract/modelmgr/modelmock"
|
||||
crossplugin "github.com/coze-dev/coze-studio/backend/crossdomain/contract/plugin"
|
||||
@ -77,6 +84,9 @@ import (
|
||||
crossuser "github.com/coze-dev/coze-studio/backend/crossdomain/contract/user"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/impl/code"
|
||||
pluginImpl "github.com/coze-dev/coze-studio/backend/crossdomain/impl/plugin"
|
||||
agententity "github.com/coze-dev/coze-studio/backend/domain/conversation/agentrun/entity"
|
||||
conventity "github.com/coze-dev/coze-studio/backend/domain/conversation/conversation/entity"
|
||||
msgentity "github.com/coze-dev/coze-studio/backend/domain/conversation/message/entity"
|
||||
entity4 "github.com/coze-dev/coze-studio/backend/domain/memory/database/entity"
|
||||
entity2 "github.com/coze-dev/coze-studio/backend/domain/openauth/openapiauth/entity"
|
||||
entity3 "github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
@ -101,6 +111,7 @@ import (
|
||||
storageMock "github.com/coze-dev/coze-studio/backend/internal/mock/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/internal/testutil"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"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"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
@ -129,6 +140,9 @@ type wfTestRunner struct {
|
||||
knowledge *knowledgemock.MockKnowledge
|
||||
database *databasemock.MockDatabase
|
||||
pluginSrv *pluginmock.MockPluginService
|
||||
conversation *conversationmock.MockConversation
|
||||
message *messagemock.MockMessage
|
||||
agentRun *agentrunmock.MockAgentRun
|
||||
internalModel *testutil.UTChatModel
|
||||
publishPatcher *mockey.Mocker
|
||||
ctx context.Context
|
||||
@ -136,29 +150,33 @@ type wfTestRunner struct {
|
||||
}
|
||||
|
||||
var req2URL = map[reflect.Type]string{
|
||||
reflect.TypeOf(&workflow.NodeTemplateListRequest{}): "/api/workflow_api/node_template_list",
|
||||
reflect.TypeOf(&workflow.CreateWorkflowRequest{}): "/api/workflow_api/create",
|
||||
reflect.TypeOf(&workflow.SaveWorkflowRequest{}): "/api/workflow_api/save",
|
||||
reflect.TypeOf(&workflow.DeleteWorkflowRequest{}): "/api/workflow_api/delete",
|
||||
reflect.TypeOf(&workflow.GetCanvasInfoRequest{}): "/api/workflow_api/canvas",
|
||||
reflect.TypeOf(&workflow.WorkFlowTestRunRequest{}): "/api/workflow_api/test_run",
|
||||
reflect.TypeOf(&workflow.CancelWorkFlowRequest{}): "/api/workflow_api/cancel",
|
||||
reflect.TypeOf(&workflow.PublishWorkflowRequest{}): "/api/workflow_api/publish",
|
||||
reflect.TypeOf(&workflow.OpenAPIRunFlowRequest{}): "/v1/workflow/run",
|
||||
reflect.TypeOf(&workflow.ValidateTreeRequest{}): "/api/workflow_api/validate_tree",
|
||||
reflect.TypeOf(&workflow.WorkflowTestResumeRequest{}): "/api/workflow_api/test_resume",
|
||||
reflect.TypeOf(&workflow.WorkflowNodeDebugV2Request{}): "/api/workflow_api/nodeDebug",
|
||||
reflect.TypeOf(&workflow.QueryWorkflowNodeTypeRequest{}): "/api/workflow_api/node_type",
|
||||
reflect.TypeOf(&workflow.GetWorkFlowListRequest{}): "/api/workflow_api/workflow_list",
|
||||
reflect.TypeOf(&workflow.UpdateWorkflowMetaRequest{}): "/api/workflow_api/update_meta",
|
||||
reflect.TypeOf(&workflow.GetWorkflowDetailRequest{}): "/api/workflow_api/workflow_detail",
|
||||
reflect.TypeOf(&workflow.GetWorkflowDetailInfoRequest{}): "/api/workflow_api/workflow_detail_info",
|
||||
reflect.TypeOf(&workflow.GetLLMNodeFCSettingDetailRequest{}): "/api/workflow_api/llm_fc_setting_detail",
|
||||
reflect.TypeOf(&workflow.GetLLMNodeFCSettingsMergedRequest{}): "/api/workflow_api/llm_fc_setting_merged",
|
||||
reflect.TypeOf(&workflow.CopyWorkflowRequest{}): "/api/workflow_api/copy",
|
||||
reflect.TypeOf(&workflow.BatchDeleteWorkflowRequest{}): "/api/workflow_api/batch_delete",
|
||||
reflect.TypeOf(&workflow.GetHistorySchemaRequest{}): "/api/workflow_api/history_schema",
|
||||
reflect.TypeOf(&workflow.GetWorkflowReferencesRequest{}): "/api/workflow_api/workflow_references",
|
||||
reflect.TypeOf(&workflow.NodeTemplateListRequest{}): "/api/workflow_api/node_template_list",
|
||||
reflect.TypeOf(&workflow.CreateWorkflowRequest{}): "/api/workflow_api/create",
|
||||
reflect.TypeOf(&workflow.SaveWorkflowRequest{}): "/api/workflow_api/save",
|
||||
reflect.TypeOf(&workflow.DeleteWorkflowRequest{}): "/api/workflow_api/delete",
|
||||
reflect.TypeOf(&workflow.GetCanvasInfoRequest{}): "/api/workflow_api/canvas",
|
||||
reflect.TypeOf(&workflow.WorkFlowTestRunRequest{}): "/api/workflow_api/test_run",
|
||||
reflect.TypeOf(&workflow.CancelWorkFlowRequest{}): "/api/workflow_api/cancel",
|
||||
reflect.TypeOf(&workflow.PublishWorkflowRequest{}): "/api/workflow_api/publish",
|
||||
reflect.TypeOf(&workflow.OpenAPIRunFlowRequest{}): "/v1/workflow/run",
|
||||
reflect.TypeOf(&workflow.ValidateTreeRequest{}): "/api/workflow_api/validate_tree",
|
||||
reflect.TypeOf(&workflow.WorkflowTestResumeRequest{}): "/api/workflow_api/test_resume",
|
||||
reflect.TypeOf(&workflow.WorkflowNodeDebugV2Request{}): "/api/workflow_api/nodeDebug",
|
||||
reflect.TypeOf(&workflow.QueryWorkflowNodeTypeRequest{}): "/api/workflow_api/node_type",
|
||||
reflect.TypeOf(&workflow.GetWorkFlowListRequest{}): "/api/workflow_api/workflow_list",
|
||||
reflect.TypeOf(&workflow.UpdateWorkflowMetaRequest{}): "/api/workflow_api/update_meta",
|
||||
reflect.TypeOf(&workflow.GetWorkflowDetailRequest{}): "/api/workflow_api/workflow_detail",
|
||||
reflect.TypeOf(&workflow.GetWorkflowDetailInfoRequest{}): "/api/workflow_api/workflow_detail_info",
|
||||
reflect.TypeOf(&workflow.GetLLMNodeFCSettingDetailRequest{}): "/api/workflow_api/llm_fc_setting_detail",
|
||||
reflect.TypeOf(&workflow.GetLLMNodeFCSettingsMergedRequest{}): "/api/workflow_api/llm_fc_setting_merged",
|
||||
reflect.TypeOf(&workflow.CopyWorkflowRequest{}): "/api/workflow_api/copy",
|
||||
reflect.TypeOf(&workflow.BatchDeleteWorkflowRequest{}): "/api/workflow_api/batch_delete",
|
||||
reflect.TypeOf(&workflow.GetHistorySchemaRequest{}): "/api/workflow_api/history_schema",
|
||||
reflect.TypeOf(&workflow.GetWorkflowReferencesRequest{}): "/api/workflow_api/workflow_references",
|
||||
reflect.TypeOf(&workflow.CreateProjectConversationDefRequest{}): "/api/workflow_api/project_conversation/create",
|
||||
reflect.TypeOf(&workflow.DeleteProjectConversationDefRequest{}): "/api/workflow_api/project_conversation/delete",
|
||||
reflect.TypeOf(&workflow.UpdateProjectConversationDefRequest{}): "/api/workflow_api/project_conversation/update",
|
||||
reflect.TypeOf(&workflow.ListProjectConversationRequest{}): "/api/workflow_api/project_conversation/list",
|
||||
}
|
||||
|
||||
func newWfTestRunner(t *testing.T) *wfTestRunner {
|
||||
@ -199,6 +217,10 @@ func newWfTestRunner(t *testing.T) *wfTestRunner {
|
||||
h.GET("/v1/workflow/get_run_history", OpenAPIGetWorkflowRunHistory)
|
||||
h.POST("/api/workflow_api/history_schema", GetHistorySchema)
|
||||
h.POST("/api/workflow_api/workflow_references", GetWorkflowReferences)
|
||||
h.POST("/api/workflow_api/project_conversation/create", CreateProjectConversationDef)
|
||||
h.POST("/api/workflow_api/project_conversation/delete", DeleteProjectConversationDef)
|
||||
h.POST("/api/workflow_api/project_conversation/update", UpdateProjectConversationDef)
|
||||
h.POST("/api/workflow_api/project_conversation/list", ListProjectConversationDef)
|
||||
|
||||
ctrl := gomock.NewController(t, gomock.WithOverridableExpectations())
|
||||
mockIDGen := mock.NewMockIDGenerator(ctrl)
|
||||
@ -303,6 +325,13 @@ func newWfTestRunner(t *testing.T) *wfTestRunner {
|
||||
mockPluginSrv := pluginmock.NewMockPluginService(ctrl)
|
||||
crossplugin.SetDefaultSVC(mockPluginSrv)
|
||||
|
||||
mockConversation := conversationmock.NewMockConversation(ctrl)
|
||||
crossconversation.SetDefaultSVC(mockConversation)
|
||||
mockMessage := messagemock.NewMockMessage(ctrl)
|
||||
crossmessage.SetDefaultSVC(mockMessage)
|
||||
mockAgentRun := agentrunmock.NewMockAgentRun(ctrl)
|
||||
crossagentrun.SetDefaultSVC(mockAgentRun)
|
||||
|
||||
mockey.Mock((*user.UserApplicationService).MGetUserBasicInfo).Return(&playground.MGetUserBasicInfoResponse{
|
||||
UserBasicInfoMap: make(map[string]*playground.UserBasicInfo),
|
||||
}, nil).Build()
|
||||
@ -338,6 +367,9 @@ func newWfTestRunner(t *testing.T) *wfTestRunner {
|
||||
closeFn: f,
|
||||
pluginSrv: mockPluginSrv,
|
||||
publishPatcher: publishPatcher,
|
||||
conversation: mockConversation,
|
||||
message: mockMessage,
|
||||
agentRun: mockAgentRun,
|
||||
}
|
||||
}
|
||||
|
||||
@ -614,12 +646,42 @@ func mustMarshalToString(t *testing.T, m any) string {
|
||||
return b
|
||||
}
|
||||
|
||||
func (r *wfTestRunner) testRun(id string, input map[string]string) string {
|
||||
type runOption struct {
|
||||
ProjectID *int64
|
||||
BotID *int64
|
||||
}
|
||||
type RunOptionFun func(options *runOption)
|
||||
|
||||
func withRunProjectID(pID int64) RunOptionFun {
|
||||
return func(options *runOption) {
|
||||
options.ProjectID = &pID
|
||||
}
|
||||
}
|
||||
|
||||
func withRunBotID(bID int64) RunOptionFun {
|
||||
return func(options *runOption) {
|
||||
options.BotID = &bID
|
||||
}
|
||||
}
|
||||
|
||||
func (r *wfTestRunner) testRun(id string, input map[string]string, opts ...RunOptionFun) string {
|
||||
opt := &runOption{}
|
||||
for _, o := range opts {
|
||||
o(opt)
|
||||
}
|
||||
testRunReq := &workflow.WorkFlowTestRunRequest{
|
||||
WorkflowID: id,
|
||||
Input: input,
|
||||
}
|
||||
|
||||
if opt.ProjectID != nil {
|
||||
testRunReq.ProjectID = ptr.Of(strconv.FormatInt(ptr.From(opt.ProjectID), 10))
|
||||
}
|
||||
|
||||
if opt.BotID != nil {
|
||||
testRunReq.BotID = ptr.Of(strconv.FormatInt(ptr.From(opt.BotID), 10))
|
||||
}
|
||||
|
||||
testRunResponse := post[workflow.WorkFlowTestRunResponse](r, testRunReq)
|
||||
return testRunResponse.Data.ExecuteID
|
||||
}
|
||||
@ -767,13 +829,26 @@ func (r *wfTestRunner) openapiAsyncRun(id string, input any) string {
|
||||
return runResp.GetExecuteID()
|
||||
}
|
||||
|
||||
func (r *wfTestRunner) openapiSyncRun(id string, input any) (map[string]any, string) {
|
||||
func (r *wfTestRunner) openapiSyncRun(id string, input any, opts ...RunOptionFun) (map[string]any, string) {
|
||||
opt := &runOption{}
|
||||
for _, o := range opts {
|
||||
o(opt)
|
||||
}
|
||||
|
||||
runReq := &workflow.OpenAPIRunFlowRequest{
|
||||
WorkflowID: id,
|
||||
Parameters: ptr.Of(mustMarshalToString(r.t, input)),
|
||||
IsAsync: ptr.Of(false),
|
||||
}
|
||||
|
||||
if opt.ProjectID != nil {
|
||||
runReq.ProjectID = ptr.Of(strconv.FormatInt(ptr.From(opt.ProjectID), 10))
|
||||
}
|
||||
|
||||
if opt.BotID != nil {
|
||||
runReq.BotID = ptr.Of(strconv.FormatInt(ptr.From(opt.BotID), 10))
|
||||
}
|
||||
|
||||
runResp := post[workflow.OpenAPIRunFlowResponse](r, runReq)
|
||||
output := runResp.GetData()
|
||||
var m map[string]any
|
||||
@ -4759,3 +4834,380 @@ func TestHttpImplicitDependencies(t *testing.T) {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestMessageNodes(t *testing.T) {
|
||||
mockey.PatchConvey("create message in dynamic conversation", t, func() {
|
||||
r := newWfTestRunner(t)
|
||||
defer r.closeFn()
|
||||
|
||||
cID := time.Now().Unix()
|
||||
r.conversation.EXPECT().CreateConversation(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
}, nil).AnyTimes()
|
||||
mID := time.Now().Unix()
|
||||
r.message.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&message.Message{
|
||||
ID: mID,
|
||||
}, nil).AnyTimes()
|
||||
rID := time.Now().UnixNano()
|
||||
r.agentRun.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&agententity.RunRecordMeta{
|
||||
ID: rID,
|
||||
}, nil).AnyTimes()
|
||||
sID := time.Now().UnixNano()
|
||||
r.conversation.EXPECT().GetByID(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
SectionID: sID,
|
||||
}, nil).AnyTimes()
|
||||
idStr := r.load("message/create_message.json")
|
||||
r.publish(idStr, "v0.0.1", true)
|
||||
|
||||
ret, _ := r.openapiSyncRun(idStr, map[string]string{
|
||||
"CONVERSATION_NAME": "name" + strconv.FormatInt(cID, 10),
|
||||
}, withRunProjectID(123))
|
||||
assert.Equal(t, true, ret["output"])
|
||||
assert.Equal(t, strconv.FormatInt(mID, 10), ret["mID"])
|
||||
})
|
||||
|
||||
mockey.PatchConvey("create message in static conversation", t, func() {
|
||||
r := newWfTestRunner(t)
|
||||
defer r.closeFn()
|
||||
|
||||
cID := time.Now().Unix()
|
||||
r.conversation.EXPECT().CreateConversation(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
}, nil).AnyTimes()
|
||||
createReq := &workflow.CreateProjectConversationDefRequest{
|
||||
ProjectID: "123",
|
||||
ConversationName: "name" + strconv.FormatInt(cID, 10),
|
||||
SpaceID: "123",
|
||||
}
|
||||
post[workflow.CreateProjectConversationDefResponse](r, createReq)
|
||||
mID := time.Now().Unix()
|
||||
r.message.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&message.Message{
|
||||
ID: mID,
|
||||
}, nil).AnyTimes()
|
||||
rID := time.Now().UnixNano()
|
||||
r.agentRun.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&agententity.RunRecordMeta{
|
||||
ID: rID,
|
||||
}, nil).AnyTimes()
|
||||
sID := time.Now().UnixNano()
|
||||
r.conversation.EXPECT().GetByID(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
SectionID: sID,
|
||||
}, nil).AnyTimes()
|
||||
idStr := r.load("message/create_message.json")
|
||||
testInput := map[string]string{
|
||||
"CONVERSATION_NAME": "name" + strconv.FormatInt(cID, 10),
|
||||
}
|
||||
exeID := r.testRun(idStr, testInput, withRunProjectID(123))
|
||||
e := r.getProcess(idStr, exeID)
|
||||
e.assertSuccess()
|
||||
output := e.output
|
||||
var result map[string]any
|
||||
err := sonic.Unmarshal([]byte(output), &result)
|
||||
assert.NoError(t, err, "Failed to unmarshal output JSON")
|
||||
|
||||
assert.Equal(t, true, result["output"])
|
||||
assert.Equal(t, strconv.FormatInt(mID, 10), result["mID"])
|
||||
})
|
||||
|
||||
mockey.PatchConvey("create message in Bot scene", t, func() {
|
||||
r := newWfTestRunner(t)
|
||||
defer r.closeFn()
|
||||
cID := time.Now().Unix()
|
||||
idStr := r.load("message/create_message_in_agent.json")
|
||||
r.publish(idStr, "v0.0.1", true)
|
||||
|
||||
testInput := map[string]string{
|
||||
"CONVERSATION_NAME": "name" + strconv.FormatInt(cID, 10),
|
||||
}
|
||||
exeID := r.testRun(idStr, testInput, withRunBotID(123))
|
||||
e := r.getProcess(idStr, exeID)
|
||||
assert.Equal(t, e.status, workflow.WorkflowExeStatus_Fail)
|
||||
assert.Contains(t, e.reason, "Only default conversation allow in agent scenario")
|
||||
})
|
||||
|
||||
mockey.PatchConvey("create message without binding app nor bot", t, func() {
|
||||
r := newWfTestRunner(t)
|
||||
defer r.closeFn()
|
||||
idStr := r.load("message/create_message_in_agent.json")
|
||||
|
||||
testInput := map[string]string{
|
||||
"CONVERSATION_NAME": "Default",
|
||||
}
|
||||
exeID := r.testRun(idStr, testInput)
|
||||
e := r.getProcess(idStr, exeID)
|
||||
output := e.output
|
||||
var result map[string]any
|
||||
err := sonic.Unmarshal([]byte(output), &result)
|
||||
assert.NoError(t, err, "Failed to unmarshal output JSON")
|
||||
|
||||
assert.Equal(t, false, result["isSuccess"])
|
||||
})
|
||||
|
||||
mockey.PatchConvey("query message list in dynamic conversation", t, func() {
|
||||
r := newWfTestRunner(t)
|
||||
defer r.closeFn()
|
||||
cID := time.Now().Unix()
|
||||
r.conversation.EXPECT().CreateConversation(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
}, nil).AnyTimes()
|
||||
mID := time.Now().Unix()
|
||||
r.message.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&message.Message{
|
||||
ID: mID,
|
||||
}, nil).AnyTimes()
|
||||
rID := time.Now().UnixNano()
|
||||
r.agentRun.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&agententity.RunRecordMeta{
|
||||
ID: rID,
|
||||
}, nil).AnyTimes()
|
||||
sID := time.Now().UnixNano()
|
||||
r.conversation.EXPECT().GetByID(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
SectionID: sID,
|
||||
}, nil).AnyTimes()
|
||||
r.message.EXPECT().MessageList(gomock.Any(), gomock.Any()).Return(&message0.MessageListResponse{
|
||||
Messages: []*message0.WfMessage{
|
||||
{
|
||||
ID: mID,
|
||||
Role: "user",
|
||||
ContentType: "text",
|
||||
Text: ptr.Of("hello"),
|
||||
},
|
||||
},
|
||||
}, nil).AnyTimes()
|
||||
|
||||
idStr := r.load("message/message_list.json")
|
||||
r.publish(idStr, "v0.0.1", true)
|
||||
ret, _ := r.openapiSyncRun(idStr, map[string]string{
|
||||
"USER_INPUT": "hello",
|
||||
"CONVERSATION_NAME": "name" + strconv.FormatInt(cID, 10),
|
||||
}, withRunProjectID(123))
|
||||
|
||||
mIDStr := strconv.FormatInt(mID, 10)
|
||||
expected := []any{
|
||||
map[string]any{
|
||||
"messageId": mIDStr,
|
||||
"role": "user",
|
||||
"contentType": "text",
|
||||
"content": "hello",
|
||||
},
|
||||
}
|
||||
assert.Equal(t, expected, ret["output"])
|
||||
})
|
||||
|
||||
mockey.PatchConvey("query message list in static conversation", t, func() {
|
||||
r := newWfTestRunner(t)
|
||||
defer r.closeFn()
|
||||
cID := time.Now().Unix()
|
||||
r.conversation.EXPECT().CreateConversation(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
}, nil).AnyTimes()
|
||||
createReq := &workflow.CreateProjectConversationDefRequest{
|
||||
ProjectID: "123",
|
||||
ConversationName: "name" + strconv.FormatInt(cID, 10),
|
||||
SpaceID: "123",
|
||||
}
|
||||
post[workflow.CreateProjectConversationDefResponse](r, createReq)
|
||||
mID := time.Now().Unix()
|
||||
r.message.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&message.Message{
|
||||
ID: mID,
|
||||
}, nil).AnyTimes()
|
||||
rID := time.Now().UnixNano()
|
||||
r.agentRun.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&agententity.RunRecordMeta{
|
||||
ID: rID,
|
||||
}, nil).AnyTimes()
|
||||
sID := time.Now().UnixNano()
|
||||
r.conversation.EXPECT().GetByID(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
SectionID: sID,
|
||||
}, nil).AnyTimes()
|
||||
r.message.EXPECT().MessageList(gomock.Any(), gomock.Any()).Return(&message0.MessageListResponse{
|
||||
Messages: []*message0.WfMessage{
|
||||
{
|
||||
ID: mID,
|
||||
Role: "user",
|
||||
ContentType: "text",
|
||||
Text: ptr.Of("hello"),
|
||||
},
|
||||
},
|
||||
}, nil).AnyTimes()
|
||||
|
||||
idStr := r.load("message/message_list.json")
|
||||
testInput := map[string]string{
|
||||
"USER_INPUT": "hello",
|
||||
"CONVERSATION_NAME": "name" + strconv.FormatInt(cID, 10),
|
||||
}
|
||||
exeID := r.testRun(idStr, testInput, withRunProjectID(123))
|
||||
e := r.getProcess(idStr, exeID)
|
||||
e.assertSuccess()
|
||||
output := e.output
|
||||
var result map[string]any
|
||||
err := sonic.Unmarshal([]byte(output), &result)
|
||||
assert.NoError(t, err)
|
||||
|
||||
mIDStr := strconv.FormatInt(mID, 10)
|
||||
expected := []any{
|
||||
map[string]any{
|
||||
"messageId": mIDStr,
|
||||
"role": "user",
|
||||
"contentType": "text",
|
||||
"content": "hello",
|
||||
},
|
||||
}
|
||||
assert.Equal(t, expected, result["output"])
|
||||
})
|
||||
|
||||
mockey.PatchConvey("edit message in dynamic conversation", t, func() {
|
||||
r := newWfTestRunner(t)
|
||||
defer r.closeFn()
|
||||
cID := time.Now().Unix()
|
||||
r.conversation.EXPECT().CreateConversation(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
}, nil).AnyTimes()
|
||||
mID := time.Now().Unix()
|
||||
r.message.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&message.Message{
|
||||
ID: mID,
|
||||
}, nil).AnyTimes()
|
||||
rID := time.Now().UnixNano()
|
||||
r.agentRun.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&agententity.RunRecordMeta{
|
||||
ID: rID,
|
||||
}, nil).AnyTimes()
|
||||
sID := time.Now().UnixNano()
|
||||
r.conversation.EXPECT().GetByID(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
SectionID: sID,
|
||||
}, nil).AnyTimes()
|
||||
r.message.EXPECT().Edit(gomock.Any(), gomock.Any()).Return(&message.Message{
|
||||
ID: mID,
|
||||
ConversationID: cID,
|
||||
}, nil).AnyTimes()
|
||||
r.message.EXPECT().GetMessageByID(gomock.Any(), gomock.Any()).Return(&msgentity.Message{
|
||||
ID: mID,
|
||||
ConversationID: cID,
|
||||
Content: "123",
|
||||
}, nil).AnyTimes()
|
||||
|
||||
idStr := r.load("message/edit_message.json")
|
||||
r.publish(idStr, "v0.0.1", true)
|
||||
ret, _ := r.openapiSyncRun(idStr, map[string]string{
|
||||
"USER_INPUT": "hello",
|
||||
"CONVERSATION_NAME": "name" + strconv.FormatInt(cID, 10),
|
||||
}, withRunProjectID(123))
|
||||
|
||||
assert.Equal(t, true, ret["isSuccess"])
|
||||
})
|
||||
|
||||
mockey.PatchConvey("edit message in static conversation", t, func() {
|
||||
r := newWfTestRunner(t)
|
||||
defer r.closeFn()
|
||||
cID := time.Now().Unix()
|
||||
r.conversation.EXPECT().CreateConversation(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
}, nil).AnyTimes()
|
||||
createReq := &workflow.CreateProjectConversationDefRequest{
|
||||
ProjectID: "123",
|
||||
ConversationName: "name" + strconv.FormatInt(cID, 10),
|
||||
SpaceID: "123",
|
||||
}
|
||||
post[workflow.CreateProjectConversationDefResponse](r, createReq)
|
||||
mID := time.Now().Unix()
|
||||
r.message.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&message.Message{
|
||||
ID: mID,
|
||||
}, nil).AnyTimes()
|
||||
rID := time.Now().UnixNano()
|
||||
r.agentRun.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&agententity.RunRecordMeta{
|
||||
ID: rID,
|
||||
}, nil).AnyTimes()
|
||||
sID := time.Now().UnixNano()
|
||||
r.conversation.EXPECT().GetByID(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
SectionID: sID,
|
||||
}, nil).AnyTimes()
|
||||
r.message.EXPECT().Edit(gomock.Any(), gomock.Any()).Return(&message.Message{
|
||||
ID: mID,
|
||||
ConversationID: cID,
|
||||
}, nil).AnyTimes()
|
||||
r.message.EXPECT().GetMessageByID(gomock.Any(), gomock.Any()).Return(&msgentity.Message{
|
||||
ID: mID,
|
||||
ConversationID: cID,
|
||||
Content: "123",
|
||||
}, nil).AnyTimes()
|
||||
|
||||
idStr := r.load("message/edit_message.json")
|
||||
testInput := map[string]string{
|
||||
"USER_INPUT": "hello",
|
||||
"CONVERSATION_NAME": "name" + strconv.FormatInt(cID, 10),
|
||||
}
|
||||
exeID := r.testRun(idStr, testInput, withRunProjectID(123))
|
||||
e := r.getProcess(idStr, exeID)
|
||||
e.assertSuccess()
|
||||
output := e.output
|
||||
var result map[string]any
|
||||
err := sonic.Unmarshal([]byte(output), &result)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, true, result["isSuccess"])
|
||||
})
|
||||
|
||||
mockey.PatchConvey("edit message no permission", t, func() {
|
||||
r := newWfTestRunner(t)
|
||||
defer r.closeFn()
|
||||
cID := time.Now().Unix()
|
||||
r.conversation.EXPECT().CreateConversation(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
}, nil).AnyTimes()
|
||||
err := errorx.New(errno.ErrMessageNodeOperationFail, errorx.KV("cause", "message not found"))
|
||||
r.message.EXPECT().Edit(gomock.Any(), gomock.Any()).Return(&message.Message{}, err).AnyTimes()
|
||||
r.message.EXPECT().GetMessageByID(gomock.Any(), gomock.Any()).Return(&msgentity.Message{
|
||||
ConversationID: cID,
|
||||
Content: "123456",
|
||||
}, nil).AnyTimes()
|
||||
sID := time.Now().UnixNano()
|
||||
r.conversation.EXPECT().GetByID(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
SectionID: sID,
|
||||
}, nil).AnyTimes()
|
||||
|
||||
idStr := r.load("message/edit_message_no_permission.json")
|
||||
r.publish(idStr, "v0.0.1", true)
|
||||
|
||||
testInput := map[string]string{
|
||||
"CONVERSATION_NAME": "name" + strconv.FormatInt(cID, 10),
|
||||
}
|
||||
exeID := r.testRun(idStr, testInput, withRunProjectID(123))
|
||||
e := r.getProcess(idStr, exeID)
|
||||
assert.Equal(t, e.status, workflow.WorkflowExeStatus_Fail)
|
||||
assert.Contains(t, e.reason, "Message node operation failure: message not found")
|
||||
})
|
||||
|
||||
mockey.PatchConvey("delete message", t, func() {
|
||||
r := newWfTestRunner(t)
|
||||
defer r.closeFn()
|
||||
cID := time.Now().Unix()
|
||||
r.conversation.EXPECT().CreateConversation(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
}, nil).AnyTimes()
|
||||
mID := time.Now().Unix()
|
||||
r.message.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&message.Message{
|
||||
ID: mID,
|
||||
}, nil).AnyTimes()
|
||||
rID := time.Now().UnixNano()
|
||||
r.agentRun.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&agententity.RunRecordMeta{
|
||||
ID: rID,
|
||||
}, nil).AnyTimes()
|
||||
sID := time.Now().UnixNano()
|
||||
r.conversation.EXPECT().GetByID(gomock.Any(), gomock.Any()).Return(&conventity.Conversation{
|
||||
ID: cID,
|
||||
SectionID: sID,
|
||||
}, nil).AnyTimes()
|
||||
r.message.EXPECT().Delete(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
|
||||
idStr := r.load("message/delete_message.json")
|
||||
r.publish(idStr, "v0.0.1", true)
|
||||
ret, _ := r.openapiSyncRun(idStr, map[string]string{
|
||||
"USER_INPUT": "hello",
|
||||
"CONVERSATION_NAME": "name" + strconv.FormatInt(cID, 10),
|
||||
}, withRunProjectID(123))
|
||||
|
||||
assert.Equal(t, true, ret["isSuccess"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/domain/conversation/agentrun/entity"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination agentrunmock/agent_run_mock.go --package agentrunmock -source agent_run.go
|
||||
type AgentRun interface {
|
||||
Delete(ctx context.Context, runID []int64) error
|
||||
List(ctx context.Context, ListMeta *entity.ListRunRecordMeta) ([]*entity.RunRecordMeta, error)
|
||||
|
||||
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: agent_run.go
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -destination agentrunmock/agent_run_mock.go --package agentrunmock -source agent_run.go
|
||||
//
|
||||
|
||||
// Package agentrunmock is a generated GoMock package.
|
||||
package agentrunmock
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
entity "github.com/coze-dev/coze-studio/backend/domain/conversation/agentrun/entity"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockAgentRun is a mock of AgentRun interface.
|
||||
type MockAgentRun struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockAgentRunMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockAgentRunMockRecorder is the mock recorder for MockAgentRun.
|
||||
type MockAgentRunMockRecorder struct {
|
||||
mock *MockAgentRun
|
||||
}
|
||||
|
||||
// NewMockAgentRun creates a new mock instance.
|
||||
func NewMockAgentRun(ctrl *gomock.Controller) *MockAgentRun {
|
||||
mock := &MockAgentRun{ctrl: ctrl}
|
||||
mock.recorder = &MockAgentRunMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockAgentRun) EXPECT() *MockAgentRunMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Create mocks base method.
|
||||
func (m *MockAgentRun) Create(ctx context.Context, runRecord *entity.AgentRunMeta) (*entity.RunRecordMeta, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Create", ctx, runRecord)
|
||||
ret0, _ := ret[0].(*entity.RunRecordMeta)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Create indicates an expected call of Create.
|
||||
func (mr *MockAgentRunMockRecorder) Create(ctx, runRecord any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockAgentRun)(nil).Create), ctx, runRecord)
|
||||
}
|
||||
|
||||
// Delete mocks base method.
|
||||
func (m *MockAgentRun) Delete(ctx context.Context, runID []int64) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Delete", ctx, runID)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Delete indicates an expected call of Delete.
|
||||
func (mr *MockAgentRunMockRecorder) Delete(ctx, runID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockAgentRun)(nil).Delete), ctx, runID)
|
||||
}
|
||||
|
||||
// List mocks base method.
|
||||
func (m *MockAgentRun) List(ctx context.Context, ListMeta *entity.ListRunRecordMeta) ([]*entity.RunRecordMeta, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "List", ctx, ListMeta)
|
||||
ret0, _ := ret[0].([]*entity.RunRecordMeta)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// List indicates an expected call of List.
|
||||
func (mr *MockAgentRunMockRecorder) List(ctx, ListMeta any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockAgentRun)(nil).List), ctx, ListMeta)
|
||||
}
|
||||
@ -0,0 +1,189 @@
|
||||
{
|
||||
"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": -222,
|
||||
"y": 48.72071651807994
|
||||
}
|
||||
},
|
||||
"type": "1"
|
||||
},
|
||||
{
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"input": {
|
||||
"type": "boolean",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "176091",
|
||||
"name": "isSuccess",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 3
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "isSuccess"
|
||||
}
|
||||
],
|
||||
"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": 1027.5,
|
||||
"y": 46.510710144593645
|
||||
}
|
||||
},
|
||||
"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": "123",
|
||||
"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": "176091",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 438.75,
|
||||
"y": 35.72071651807994
|
||||
}
|
||||
},
|
||||
"type": "55"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "176091",
|
||||
"sourcePortID": ""
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "176091",
|
||||
"targetNodeID": "900001",
|
||||
"sourcePortID": ""
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,317 @@
|
||||
{
|
||||
"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": -212,
|
||||
"y": -22.069277108433766
|
||||
}
|
||||
},
|
||||
"type": "1"
|
||||
},
|
||||
{
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"input": {
|
||||
"type": "boolean",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "140767",
|
||||
"name": "isSuccess",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 3
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "isSuccess"
|
||||
}
|
||||
],
|
||||
"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": 1027.5,
|
||||
"y": 46.510710144593645
|
||||
}
|
||||
},
|
||||
"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-Create.jpeg",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "创建会话",
|
||||
"title": "创建会话"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "isSuccess",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "isExisted",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "conversationId",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "100911",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 23.75,
|
||||
"y": 207.72071651807994
|
||||
}
|
||||
},
|
||||
"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": "123",
|
||||
"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": "176091",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 272.75,
|
||||
"y": -173.27928348192006
|
||||
}
|
||||
},
|
||||
"type": "55"
|
||||
},
|
||||
{
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "100001",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"source": "block-output"
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "conversationName"
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "176091",
|
||||
"name": "message.messageId",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "messageId"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "140767",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 616.75,
|
||||
"y": 73.72071651807994
|
||||
}
|
||||
},
|
||||
"type": "57"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "100911",
|
||||
"sourcePortID": ""
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "140767",
|
||||
"targetNodeID": "900001",
|
||||
"sourcePortID": ""
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "100911",
|
||||
"targetNodeID": "176091",
|
||||
"sourcePortID": ""
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "176091",
|
||||
"targetNodeID": "140767",
|
||||
"sourcePortID": ""
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,333 @@
|
||||
{
|
||||
"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": -212,
|
||||
"y": -22.069277108433766
|
||||
}
|
||||
},
|
||||
"type": "1"
|
||||
},
|
||||
{
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"input": {
|
||||
"type": "boolean",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "191842",
|
||||
"name": "isSuccess",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 3
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "isSuccess"
|
||||
}
|
||||
],
|
||||
"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": 1027.5,
|
||||
"y": 46.510710144593645
|
||||
}
|
||||
},
|
||||
"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-Create.jpeg",
|
||||
"mainColor": "#F2B600",
|
||||
"subTitle": "创建会话",
|
||||
"title": "创建会话"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "isSuccess",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "isExisted",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "conversationId",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "100911",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 23.75,
|
||||
"y": 207.72071651807994
|
||||
}
|
||||
},
|
||||
"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": "123",
|
||||
"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": "176091",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 272.75,
|
||||
"y": -173.27928348192006
|
||||
}
|
||||
},
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "176091",
|
||||
"name": "message.messageId",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "messageId"
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": "修改消息",
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "literal"
|
||||
}
|
||||
},
|
||||
"name": "newContent"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "191842",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 541.75,
|
||||
"y": 46.510710144593645
|
||||
}
|
||||
},
|
||||
"type": "56"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "100911",
|
||||
"sourcePortID": ""
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "191842",
|
||||
"targetNodeID": "900001",
|
||||
"sourcePortID": ""
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "100911",
|
||||
"targetNodeID": "176091",
|
||||
"sourcePortID": ""
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "176091",
|
||||
"targetNodeID": "191842",
|
||||
"sourcePortID": ""
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,228 @@
|
||||
{
|
||||
"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": -222,
|
||||
"y": 48.72071651807994
|
||||
}
|
||||
},
|
||||
"type": "1"
|
||||
},
|
||||
{
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"input": {
|
||||
"type": "boolean",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "112184",
|
||||
"name": "isSuccess",
|
||||
"source": "block-output"
|
||||
},
|
||||
"rawMeta": {
|
||||
"type": 3
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "isSuccess"
|
||||
}
|
||||
],
|
||||
"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": 1092.75,
|
||||
"y": 46.510710144593645
|
||||
}
|
||||
},
|
||||
"type": "2"
|
||||
},
|
||||
{
|
||||
"blocks": [],
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [
|
||||
{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": {
|
||||
"blockID": "100001",
|
||||
"name": "CONVERSATION_NAME",
|
||||
"source": "block-output"
|
||||
},
|
||||
"type": "ref"
|
||||
}
|
||||
},
|
||||
"name": "conversationName"
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": "123",
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "literal"
|
||||
}
|
||||
},
|
||||
"name": "messageId"
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"type": "string",
|
||||
"value": {
|
||||
"content": "123",
|
||||
"rawMeta": {
|
||||
"type": 1
|
||||
},
|
||||
"type": "literal"
|
||||
}
|
||||
},
|
||||
"name": "newContent"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"edges": null,
|
||||
"id": "112184",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 598,
|
||||
"y": 35.72071651807994
|
||||
}
|
||||
},
|
||||
"type": "56"
|
||||
},
|
||||
{
|
||||
"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": "146209",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 188,
|
||||
"y": 35.72071651807994
|
||||
}
|
||||
},
|
||||
"type": "39"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "146209",
|
||||
"sourcePortID": ""
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "112184",
|
||||
"targetNodeID": "900001",
|
||||
"sourcePortID": ""
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "146209",
|
||||
"targetNodeID": "112184",
|
||||
"sourcePortID": ""
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"loop": "v2"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user