feat(workflow): add unit tests for message-related nodes (#1889)

main
lvxinyu-1117 2 months ago committed by GitHub
parent 3abf492f6d
commit b257802c7e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 506
      backend/api/handler/coze/workflow_service_test.go
  2. 1
      backend/crossdomain/contract/agentrun/agent_run.go
  3. 102
      backend/crossdomain/contract/agentrun/agentrunmock/agent_run_mock.go
  4. 189
      backend/domain/workflow/internal/canvas/examples/message/create_message_in_agent.json
  5. 317
      backend/domain/workflow/internal/canvas/examples/message/delete_message.json
  6. 333
      backend/domain/workflow/internal/canvas/examples/message/edit_message.json
  7. 228
      backend/domain/workflow/internal/canvas/examples/message/edit_message_no_permission.json

@ -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"
}
}
Loading…
Cancel
Save