feat: Support for Chat Flow & Agent Support for binding a single chat flow (#765)

Co-authored-by: Yu Yang <72337138+tomasyu985@users.noreply.github.com>
Co-authored-by: zengxiaohui <csu.zengxiaohui@gmail.com>
Co-authored-by: lijunwen.gigoo <lijunwen.gigoo@bytedance.com>
Co-authored-by: lvxinyu.1117 <lvxinyu.1117@bytedance.com>
Co-authored-by: liuyunchao.0510 <liuyunchao.0510@bytedance.com>
Co-authored-by: haozhenfei <37089575+haozhenfei@users.noreply.github.com>
Co-authored-by: July <jiangxujin@bytedance.com>
Co-authored-by: tecvan-fe <fanwenjie.fe@bytedance.com>
This commit is contained in:
Zhj
2025-08-28 21:53:32 +08:00
committed by GitHub
parent bbc615a18e
commit d70101c979
503 changed files with 48036 additions and 3427 deletions

View File

@@ -24,6 +24,7 @@ import (
"github.com/cloudwego/eino/schema"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
conventity "github.com/coze-dev/coze-studio/backend/domain/conversation/conversation/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/config"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
@@ -55,12 +56,41 @@ type AsTool interface {
allInterruptEvents map[string]*entity.ToolInterruptEvent) compose.Option
}
type ChatFlowRole interface {
CreateChatFlowRole(ctx context.Context, role *vo.ChatFlowRoleCreate) (int64, error)
UpdateChatFlowRole(ctx context.Context, workflowID int64, role *vo.ChatFlowRoleUpdate) error
GetChatFlowRole(ctx context.Context, workflowID int64, version string) (*entity.ChatFlowRole, error)
DeleteChatFlowRole(ctx context.Context, id int64, workflowID int64) error
PublishChatFlowRole(ctx context.Context, policy *vo.PublishRolePolicy) error
}
type Conversation interface {
CreateDraftConversationTemplate(ctx context.Context, template *vo.CreateConversationTemplateMeta) (int64, error)
UpdateDraftConversationTemplateName(ctx context.Context, appID int64, userID int64, templateID int64, name string) error
DeleteDraftConversationTemplate(ctx context.Context, templateID int64, wfID2ConversationName map[int64]string) (int64, error)
CheckWorkflowsToReplace(ctx context.Context, appID int64, templateID int64) ([]*entity.Workflow, error)
DeleteDynamicConversation(ctx context.Context, env vo.Env, templateID int64) (int64, error)
ListConversationTemplate(ctx context.Context, env vo.Env, policy *vo.ListConversationTemplatePolicy) ([]*entity.ConversationTemplate, error)
MGetStaticConversation(ctx context.Context, env vo.Env, userID, connectorID int64, templateIDs []int64) ([]*entity.StaticConversation, error)
ListDynamicConversation(ctx context.Context, env vo.Env, policy *vo.ListConversationPolicy) ([]*entity.DynamicConversation, error)
ReleaseConversationTemplate(ctx context.Context, appID int64, version string) error
InitApplicationDefaultConversationTemplate(ctx context.Context, spaceID int64, appID int64, userID int64) error
GetOrCreateConversation(ctx context.Context, env vo.Env, appID, connectorID, userID int64, conversationName string) (int64, int64, error)
UpdateConversation(ctx context.Context, env vo.Env, appID, connectorID, userID int64, conversationName string) (int64, error)
GetTemplateByName(ctx context.Context, env vo.Env, appID int64, templateName string) (*entity.ConversationTemplate, bool, error)
GetDynamicConversationByName(ctx context.Context, env vo.Env, appID, connectorID, userID int64, name string) (*entity.DynamicConversation, bool, error)
GetConversationNameByID(ctx context.Context, env vo.Env, appID, connectorID, conversationID int64) (string, bool, error)
}
type InterruptEventStore interface {
SaveInterruptEvents(ctx context.Context, wfExeID int64, events []*entity.InterruptEvent) error
GetFirstInterruptEvent(ctx context.Context, wfExeID int64) (*entity.InterruptEvent, bool, error)
UpdateFirstInterruptEvent(ctx context.Context, wfExeID int64, event *entity.InterruptEvent) error
PopFirstInterruptEvent(ctx context.Context, wfExeID int64) (*entity.InterruptEvent, bool, error)
ListInterruptEvents(ctx context.Context, wfExeID int64) ([]*entity.InterruptEvent, error)
BindConvRelatedInfo(ctx context.Context, convID int64, info entity.ConvRelatedInfo) error
GetConvRelatedInfo(ctx context.Context, convID int64) (*entity.ConvRelatedInfo, bool, func() error, error)
}
type CancelSignalStore interface {
@@ -93,6 +123,33 @@ type ToolFromWorkflow interface {
GetWorkflow() *entity.Workflow
}
type ConversationIDGenerator func(ctx context.Context, appID int64, userID, connectorID int64) (*conventity.Conversation, error)
type ConversationRepository interface {
CreateDraftConversationTemplate(ctx context.Context, template *vo.CreateConversationTemplateMeta) (int64, error)
UpdateDraftConversationTemplateName(ctx context.Context, templateID int64, name string) error
DeleteDraftConversationTemplate(ctx context.Context, templateID int64) (int64, error)
GetConversationTemplate(ctx context.Context, env vo.Env, policy vo.GetConversationTemplatePolicy) (*entity.ConversationTemplate, bool, error)
DeleteDynamicConversation(ctx context.Context, env vo.Env, id int64) (int64, error)
ListConversationTemplate(ctx context.Context, env vo.Env, policy *vo.ListConversationTemplatePolicy) ([]*entity.ConversationTemplate, error)
MGetStaticConversation(ctx context.Context, env vo.Env, userID, connectorID int64, templateIDs []int64) ([]*entity.StaticConversation, error)
GetOrCreateStaticConversation(ctx context.Context, env vo.Env, idGen ConversationIDGenerator, meta *vo.CreateStaticConversation) (int64, int64, bool, error)
GetOrCreateDynamicConversation(ctx context.Context, env vo.Env, idGen ConversationIDGenerator, meta *vo.CreateDynamicConversation) (int64, int64, bool, error)
GetDynamicConversationByName(ctx context.Context, env vo.Env, appID, connectorID, userID int64, name string) (*entity.DynamicConversation, bool, error)
GetStaticConversationByTemplateID(ctx context.Context, env vo.Env, userID, connectorID, templateID int64) (*entity.StaticConversation, bool, error)
ListDynamicConversation(ctx context.Context, env vo.Env, policy *vo.ListConversationPolicy) ([]*entity.DynamicConversation, error)
BatchCreateOnlineConversationTemplate(ctx context.Context, templates []*entity.ConversationTemplate, version string) error
UpdateDynamicConversationNameByID(ctx context.Context, env vo.Env, templateID int64, name string) error
UpdateStaticConversation(ctx context.Context, env vo.Env, templateID int64, connectorID int64, userID int64, newConversationID int64) error
UpdateDynamicConversation(ctx context.Context, env vo.Env, conversationID, newConversationID int64) error
CopyTemplateConversationByAppID(ctx context.Context, appID int64, toAppID int64) error
GetStaticConversationByID(ctx context.Context, env vo.Env, appID, connectorID, conversationID int64) (string, bool, error)
GetDynamicConversationByID(ctx context.Context, env vo.Env, appID, connectorID, conversationID int64) (*entity.DynamicConversation, bool, error)
}
type WorkflowConfig interface {
GetNodeOfCodeConfig() *config.NodeOfCodeConfig
}
type Suggester interface {
Suggest(ctx context.Context, input *vo.SuggestInfo) ([]string, error)
}

View File

@@ -20,7 +20,7 @@ type WorkflowConfig struct {
NodeOfCodeConfig *NodeOfCodeConfig `yaml:"NodeOfCodeConfig"`
}
func (w WorkflowConfig) GetNodeOfCodeConfig() *NodeOfCodeConfig {
func (w *WorkflowConfig) GetNodeOfCodeConfig() *NodeOfCodeConfig {
return w.NodeOfCodeConfig
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package entity
import "time"
type ChatFlowRole struct {
ID int64
WorkflowID int64
ConnectorID int64
Name string
Description string
Version string
AvatarUri string
BackgroundImageInfo string
OnboardingInfo string
SuggestReplyInfo string
AudioConfig string
UserInputConfig string
CreatorID int64
CreatedAt time.Time
UpdatedAt time.Time
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package entity
type ConversationTemplate struct {
SpaceID int64
AppID int64
Name string
TemplateID int64
}
type StaticConversation struct {
UserID int64
ConnectorID int64
TemplateID int64
ConversationID int64
}
type DynamicConversation struct {
ID int64
UserID int64
ConnectorID int64
ConversationID int64
Name string
}

View File

@@ -74,3 +74,9 @@ type ToolInterruptEvent struct {
ExecuteID int64
*InterruptEvent
}
type ConvRelatedInfo struct {
EventID int64
ExecID int64
NodeType NodeType
}

View File

@@ -144,8 +144,11 @@ const (
NodeTypeCodeRunner NodeType = "CodeRunner"
NodeTypePlugin NodeType = "Plugin"
NodeTypeCreateConversation NodeType = "CreateConversation"
NodeTypeConversationList NodeType = "ConversationList"
NodeTypeMessageList NodeType = "MessageList"
NodeTypeClearMessage NodeType = "ClearMessage"
NodeTypeCreateMessage NodeType = "CreateMessage"
NodeTypeEditMessage NodeType = "EditMessage"
NodeTypeDeleteMessage NodeType = "DeleteMessage"
NodeTypeLambda NodeType = "Lambda"
NodeTypeLLM NodeType = "LLM"
NodeTypeSelector NodeType = "Selector"
@@ -153,6 +156,10 @@ const (
NodeTypeSubWorkflow NodeType = "SubWorkflow"
NodeTypeJsonSerialization NodeType = "JsonSerialization"
NodeTypeJsonDeserialization NodeType = "JsonDeserialization"
NodeTypeConversationUpdate NodeType = "ConversationUpdate"
NodeTypeConversationDelete NodeType = "ConversationDelete"
NodeTypeClearConversationHistory NodeType = "ClearConversationHistory"
NodeTypeConversationHistory NodeType = "ConversationHistory"
NodeTypeComment NodeType = "Comment"
)
@@ -272,6 +279,7 @@ var NodeTypeMetas = map[NodeType]*NodeTypeMeta{
PostFillNil: true,
InputSourceAware: true,
MayUseChatModel: true,
UseCtxCache: true,
},
EnUSName: "LLM",
EnUSDescription: "Invoke the large language model, generate responses using variables and prompt words.",
@@ -324,6 +332,7 @@ var NodeTypeMetas = map[NodeType]*NodeTypeMeta{
ExecutableMeta: ExecutableMeta{
PreFillZero: true,
PostFillNil: true,
UseCtxCache: true,
},
EnUSName: "Knowledge retrieval",
EnUSDescription: "In the selected knowledge, the best matching information is recalled based on the input variable and returned as an Array.",
@@ -487,6 +496,7 @@ var NodeTypeMetas = map[NodeType]*NodeTypeMeta{
PreFillZero: true,
PostFillNil: true,
MayUseChatModel: true,
UseCtxCache: true,
},
EnUSName: "Intent recognition",
EnUSDescription: "Used for recognizing the intent in user input and matching it with preset intent options.",
@@ -593,7 +603,6 @@ var NodeTypeMetas = map[NodeType]*NodeTypeMeta{
Color: "#F2B600",
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-List.jpeg",
SupportBatch: false,
Disabled: true,
ExecutableMeta: ExecutableMeta{
PreFillZero: true,
PostFillNil: true,
@@ -601,16 +610,15 @@ var NodeTypeMetas = map[NodeType]*NodeTypeMeta{
EnUSName: "Query message list",
EnUSDescription: "Used to query the message list",
},
NodeTypeClearMessage: {
NodeTypeClearConversationHistory: {
ID: 38,
Key: NodeTypeClearMessage,
Name: "清除上下文",
Category: "conversation_history",
Key: NodeTypeClearConversationHistory,
Name: "清空会话历史",
Category: "conversation_history", // Mapped from cate_list
Desc: "用于清空会话历史清空后LLM看到的会话历史为空",
Color: "#F2B600",
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Delete.jpeg",
SupportBatch: false,
Disabled: true,
SupportBatch: false, // supportBatch: 1
ExecutableMeta: ExecutableMeta{
PreFillZero: true,
PostFillNil: true,
@@ -627,7 +635,6 @@ var NodeTypeMetas = map[NodeType]*NodeTypeMeta{
Color: "#F2B600",
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
SupportBatch: false,
Disabled: true,
ExecutableMeta: ExecutableMeta{
PreFillZero: true,
PostFillNil: true,
@@ -730,6 +737,118 @@ var NodeTypeMetas = map[NodeType]*NodeTypeMeta{
EnUSName: "Add Data",
EnUSDescription: "Add new data records to the table, and insert them into the database after the user enters the data content",
},
NodeTypeConversationUpdate: {
ID: 51,
Name: "修改会话",
Key: NodeTypeConversationUpdate,
Category: "conversation_management",
Desc: "用于修改会话的名字",
Color: "#F2B600",
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-编辑会话.jpg",
SupportBatch: false,
ExecutableMeta: ExecutableMeta{
PreFillZero: true,
PostFillNil: true,
},
EnUSName: "Edit Conversation",
EnUSDescription: "Used to modify the name of a conversation.",
},
NodeTypeConversationDelete: {
ID: 52,
Name: "删除会话",
Key: NodeTypeConversationDelete,
Category: "conversation_management",
Desc: "用于删除会话",
Color: "#F2B600",
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-删除会话.jpg",
SupportBatch: false,
ExecutableMeta: ExecutableMeta{
PreFillZero: true,
PostFillNil: true,
},
EnUSName: "Delete Conversation",
EnUSDescription: "Used to delete a conversation.",
},
NodeTypeConversationList: {
ID: 53,
Name: "查询会话列表",
Key: NodeTypeConversationList,
Category: "conversation_management",
Desc: "用于查询所有会话,包含静态会话、动态会话",
Color: "#F2B600",
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-查询会话.jpg",
SupportBatch: false,
ExecutableMeta: ExecutableMeta{
PostFillNil: true,
},
EnUSName: "Query Conversation List",
EnUSDescription: "Used to query all conversations, including static conversations and dynamic conversations",
},
NodeTypeConversationHistory: {
ID: 54,
Name: "查询会话历史",
Key: NodeTypeConversationHistory,
Category: "conversation_history", // Mapped from cate_list
Desc: "用于查询会话历史返回LLM可见的会话消息",
Color: "#F2B600",
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-查询会话历史.jpg",
SupportBatch: false,
ExecutableMeta: ExecutableMeta{
PreFillZero: true,
PostFillNil: true,
},
EnUSName: "Query Conversation History",
EnUSDescription: "Used to query conversation history, returns conversation messages visible to the LLM",
},
NodeTypeCreateMessage: {
ID: 55,
Name: "创建消息",
Key: NodeTypeCreateMessage,
Category: "message",
Desc: "用于创建消息",
Color: "#F2B600",
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-创建消息.jpg",
SupportBatch: false, // supportBatch: 1
ExecutableMeta: ExecutableMeta{
PreFillZero: true,
PostFillNil: true,
},
EnUSName: "Create message",
EnUSDescription: "Used to create messages",
},
NodeTypeEditMessage: {
ID: 56,
Name: "修改消息",
Key: NodeTypeEditMessage,
Category: "message",
Desc: "用于修改消息",
Color: "#F2B600",
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-修改消息.jpg",
SupportBatch: false, // supportBatch: 1
ExecutableMeta: ExecutableMeta{
PreFillZero: true,
PostFillNil: true,
},
EnUSName: "Edit message",
EnUSDescription: "Used to edit messages",
},
NodeTypeDeleteMessage: {
ID: 57,
Name: "删除消息",
Key: NodeTypeDeleteMessage,
Category: "message",
Desc: "用于删除消息",
Color: "#F2B600",
IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-删除消息.jpg",
SupportBatch: false, // supportBatch: 1
ExecutableMeta: ExecutableMeta{
PreFillZero: true,
PostFillNil: true,
},
EnUSName: "Delete message",
EnUSDescription: "Used to delete messages",
},
NodeTypeJsonSerialization: {
// ID is the unique identifier of this node type. Used in various front-end APIs.
ID: 58,

View File

@@ -17,6 +17,8 @@
package vo
import (
"fmt"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/modelmgr"
"github.com/coze-dev/coze-studio/backend/api/model/workflow"
"github.com/coze-dev/coze-studio/backend/pkg/i18n"
@@ -108,7 +110,8 @@ type Data struct {
type Inputs struct {
// InputParameters are the fields defined by user for this particular node.
InputParameters []*Param `json:"inputParameters"`
// ChatHistorySetting configures the chat history setting for this node in chatflow mode.
ChatHistorySetting *ChatHistorySetting `json:"chatHistorySetting,omitempty"`
// SettingOnError configures common error handling strategy for nodes.
// NOTE: enable in frontend node's form first.
SettingOnError *SettingOnError `json:"settingOnError,omitempty"`
@@ -432,9 +435,8 @@ type DatabaseInfo struct {
}
type IntentDetector struct {
ChatHistorySetting *ChatHistorySetting `json:"chatHistorySetting,omitempty"`
Intents []*Intent `json:"intents,omitempty"`
Mode string `json:"mode,omitempty"`
Intents []*Intent `json:"intents,omitempty"`
Mode string `json:"mode,omitempty"`
}
type ChatHistorySetting struct {
EnableChatHistory bool `json:"enableChatHistory,omitempty"`
@@ -826,6 +828,133 @@ const defaultEnUSInitCanvasJsonSchema = `{
}
}`
const defaultZhCNInitCanvasJsonSchemaChat = `{
"nodes": [{
"id": "100001",
"type": "1",
"meta": {
"position": {
"x": 0,
"y": 0
}
},
"data": {
"outputs": [{
"type": "string",
"name": "USER_INPUT",
"required": true
}, {
"type": "string",
"name": "CONVERSATION_NAME",
"required": false,
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
"defaultValue": "%s"
}],
"nodeMeta": {
"title": "开始",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start.png",
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
"subTitle": ""
}
}
}, {
"id": "900001",
"type": "2",
"meta": {
"position": {
"x": 1000,
"y": 0
}
},
"data": {
"nodeMeta": {
"title": "结束",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End.png",
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
"subTitle": ""
},
"inputs": {
"terminatePlan": "useAnswerContent",
"streamingOutput": true,
"inputParameters": [{
"name": "output",
"input": {
"type": "string",
"value": {
"type": "ref"
}
}
}]
}
}
}]
}`
const defaultEnUSInitCanvasJsonSchemaChat = `{
"nodes": [{
"id": "100001",
"type": "1",
"meta": {
"position": {
"x": 0,
"y": 0
}
},
"data": {
"outputs": [{
"type": "string",
"name": "USER_INPUT",
"required": true
}, {
"type": "string",
"name": "CONVERSATION_NAME",
"required": false,
"description": "The conversation bound to this request will automatically write messages and read conversation history from that conversation.",
"defaultValue": "%s"
}],
"nodeMeta": {
"title": "Start",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start.png",
"description": "The starting node of the workflow, used to set the information needed to initiate the workflow.",
"subTitle": ""
}
}
}, {
"id": "900001",
"type": "2",
"meta": {
"position": {
"x": 1000,
"y": 0
}
},
"data": {
"nodeMeta": {
"title": "End",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End.png",
"description": "The final node of the workflow, used to return the result information after the workflow runs.",
"subTitle": ""
},
"inputs": {
"terminatePlan": "useAnswerContent",
"streamingOutput": true,
"inputParameters": [{
"name": "output",
"input": {
"type": "string",
"value": {
"type": "ref"
}
}
}]
}
}
}]
}`
func GetDefaultInitCanvasJsonSchema(locale i18n.Locale) string {
return ternary.IFElse(locale == i18n.LocaleEN, defaultEnUSInitCanvasJsonSchema, defaultZhCNInitCanvasJsonSchema)
}
func GetDefaultInitCanvasJsonSchemaChat(locale i18n.Locale, name string) string {
return ternary.IFElse(locale == i18n.LocaleEN, fmt.Sprintf(defaultEnUSInitCanvasJsonSchemaChat, name), fmt.Sprintf(defaultZhCNInitCanvasJsonSchemaChat, name))
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vo
type ChatFlowRoleCreate struct {
WorkflowID int64
CreatorID int64
Name string
Description string
AvatarUri string
BackgroundImageInfo string
OnboardingInfo string
SuggestReplyInfo string
AudioConfig string
UserInputConfig string
}
type ChatFlowRoleUpdate struct {
WorkflowID int64
Name *string
Description *string
AvatarUri *string
BackgroundImageInfo *string
OnboardingInfo *string
SuggestReplyInfo *string
AudioConfig *string
UserInputConfig *string
}
type PublishRolePolicy struct {
WorkflowID int64
CreatorID int64
Version string
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vo
import "github.com/cloudwego/eino/schema"
type ChatFlowEvent string
const (
ChatFlowCreated ChatFlowEvent = "conversation.chat.created"
ChatFlowInProgress ChatFlowEvent = "conversation.chat.in_progress"
ChatFlowCompleted ChatFlowEvent = "conversation.chat.completed"
ChatFlowFailed ChatFlowEvent = "conversation.chat.failed"
ChatFlowRequiresAction ChatFlowEvent = "conversation.chat.requires_action"
ChatFlowError ChatFlowEvent = "error"
ChatFlowDone ChatFlowEvent = "done"
ChatFlowMessageDelta ChatFlowEvent = "conversation.message.delta"
ChatFlowMessageCompleted ChatFlowEvent = "conversation.message.completed"
)
type Usage struct {
TokenCount *int32 `form:"token_count" json:"token_count,omitempty"`
OutputTokens *int32 `form:"output_count" json:"output_count,omitempty"`
InputTokens *int32 `form:"input_count" json:"input_count,omitempty"`
}
type Status string
const (
Created Status = "created"
InProgress Status = "in_progress"
Completed Status = "completed"
Failed Status = "failed"
RequiresAction Status = "requires_action"
Canceled Status = "canceled"
)
type ChatFlowDetail struct {
ID string `json:"id,omitempty"`
ConversationID string `json:"conversation_id,omitempty"`
BotID string `json:"bot_id,omitempty"`
Status Status `json:"status,omitempty"`
Usage *Usage `json:"usage,omitempty"`
ExecuteID string `json:"execute_id,omitempty"`
SectionID string `json:"section_id"`
}
type MessageDetail struct {
ID string `json:"id"`
ChatID string `json:"chat_id"`
ConversationID string `json:"conversation_id"`
BotID string `json:"bot_id"`
Role string `json:"role"`
Type string `json:"type"`
Content string `json:"content"`
ContentType string `json:"content_type"`
SectionID string `json:"section_id"`
}
type ErrorDetail struct {
Code string `form:"code,required" json:"code,required"`
Msg string `form:"msg,required" json:"msg,required"`
DebugUrl string `form:"debug_url" json:"debug_url,omitempty"`
}
type SuggestInfo struct {
UserInput *schema.Message `json:"user_input,omitempty"`
AnswerInput *schema.Message `json:"answer,omitempty"`
PersonaInput *string `json:"persona_input,omitempty"`
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vo
type Env string
const (
Draft Env = "draft"
Online Env = "online"
)
type CreateConversationTemplateMeta struct {
UserID int64
AppID int64
SpaceID int64
Name string
}
type GetConversationTemplatePolicy struct {
AppID *int64
Name *string
Version *string
TemplateID *int64
}
type ListConversationTemplatePolicy struct {
AppID int64
Page *Page
NameLike *string
Version *string
}
type ListConversationMeta struct {
APPID int64
UserID int64
ConnectorID int64
}
type ListConversationPolicy struct {
ListConversationMeta
Page *Page
NameLike *string
Version *string
}
type CreateStaticConversation struct {
AppID int64
UserID int64
ConnectorID int64
TemplateID int64
}
type CreateDynamicConversation struct {
AppID int64
UserID int64
ConnectorID int64
Name string
}

View File

@@ -68,6 +68,7 @@ type MetaUpdate struct {
IconURI *string
HasPublished *bool
LatestPublishedVersion *string
WorkflowMode *Mode
}
type MetaQuery struct {
@@ -80,4 +81,5 @@ type MetaQuery struct {
LibOnly bool
NeedTotalNumber bool
DescByUpdate bool
Mode *workflow.WorkflowMode
}

View File

@@ -21,4 +21,5 @@ type ReleaseWorkflowConfig struct {
PluginIDs []int64
ConnectorIDs []int64
WorkflowIDs []int64
}

View File

@@ -26,6 +26,7 @@ import (
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
)
//go:generate mockgen -destination ../../internal/mock/domain/workflow/interface.go --package mockWorkflow -source interface.go
@@ -39,12 +40,15 @@ type Service interface {
Publish(ctx context.Context, policy *vo.PublishPolicy) (err error)
UpdateMeta(ctx context.Context, id int64, metaUpdate *vo.MetaUpdate) (err error)
CopyWorkflow(ctx context.Context, workflowID int64, policy vo.CopyWorkflowPolicy) (*entity.Workflow, error)
WorkflowSchemaCheck(ctx context.Context, wf *entity.Workflow, checks []workflow.CheckType) ([]*workflow.CheckResult, error)
QueryNodeProperties(ctx context.Context, id int64) (map[string]*vo.NodeProperty, error) // only draft
ValidateTree(ctx context.Context, id int64, validateConfig vo.ValidateTreeConfig) ([]*workflow.ValidateTreeInfo, error)
GetWorkflowReference(ctx context.Context, id int64) (map[int64]*vo.Meta, error)
GetWorkflowVersionsByConnector(ctx context.Context, connectorID, workflowID int64, limit int) ([]string, error)
Executable
AsTool
@@ -53,17 +57,29 @@ type Service interface {
DuplicateWorkflowsByAppID(ctx context.Context, sourceAPPID, targetAppID int64, related vo.ExternalResourceRelated) ([]*entity.Workflow, error)
GetWorkflowDependenceResource(ctx context.Context, workflowID int64) (*vo.DependenceResource, error)
SyncRelatedWorkflowResources(ctx context.Context, appID int64, relatedWorkflows map[int64]entity.IDVersionPair, related vo.ExternalResourceRelated) error
ChatFlowRole
Conversation
BindConvRelatedInfo(ctx context.Context, convID int64, info entity.ConvRelatedInfo) error
GetConvRelatedInfo(ctx context.Context, convID int64) (*entity.ConvRelatedInfo, bool, func() error, error)
Suggest(ctx context.Context, input *vo.SuggestInfo) ([]string, error)
}
type Repository interface {
CreateMeta(ctx context.Context, meta *vo.Meta) (int64, error)
CreateVersion(ctx context.Context, id int64, info *vo.VersionInfo, newRefs map[entity.WorkflowReferenceKey]struct{}) (err error)
CreateOrUpdateDraft(ctx context.Context, id int64, draft *vo.DraftInfo) error
CreateChatFlowRoleConfig(ctx context.Context, chatFlowRole *entity.ChatFlowRole) (int64, error)
UpdateChatFlowRoleConfig(ctx context.Context, workflowID int64, chatFlowRole *vo.ChatFlowRoleUpdate) error
GetChatFlowRoleConfig(ctx context.Context, workflowID int64, version string) (*entity.ChatFlowRole, error, bool)
DeleteChatFlowRoleConfig(ctx context.Context, id int64, workflowID int64) error
Delete(ctx context.Context, id int64) error
MDelete(ctx context.Context, ids []int64) error
GetMeta(ctx context.Context, id int64) (*vo.Meta, error)
UpdateMeta(ctx context.Context, id int64, metaUpdate *vo.MetaUpdate) error
GetVersion(ctx context.Context, id int64, version string) (*vo.VersionInfo, error)
GetVersion(ctx context.Context, id int64, version string) (*vo.VersionInfo, bool, error)
GetVersionListByConnectorAndWorkflowID(ctx context.Context, connectorID, workflowID int64, limit int) ([]string, error)
GetEntity(ctx context.Context, policy *vo.GetPolicy) (*entity.Workflow, error)
@@ -95,12 +111,15 @@ type Repository interface {
IsApplicationConnectorWorkflowVersion(ctx context.Context, connectorID, workflowID int64, version string) (b bool, err error)
GetObjectUrl(ctx context.Context, objectKey string, opts ...storage.GetOptFn) (string, error)
compose.CheckPointStore
idgen.IDGenerator
GetKnowledgeRecallChatModel() model.BaseChatModel
ConversationRepository
WorkflowConfig
Suggester
}
var repositorySingleton Repository

View File

@@ -34,6 +34,7 @@ import (
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/batch"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/code"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/conversation"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/database"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/emitter"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/entry"
@@ -674,6 +675,36 @@ func RegisterAllNodeAdaptors() {
nodes.RegisterNodeAdaptor(entity.NodeTypeLLM, func() nodes.NodeAdaptor {
return &llm.Config{}
})
nodes.RegisterNodeAdaptor(entity.NodeTypeCreateConversation, func() nodes.NodeAdaptor {
return &conversation.CreateConversationConfig{}
})
nodes.RegisterNodeAdaptor(entity.NodeTypeConversationUpdate, func() nodes.NodeAdaptor {
return &conversation.UpdateConversationConfig{}
})
nodes.RegisterNodeAdaptor(entity.NodeTypeConversationDelete, func() nodes.NodeAdaptor {
return &conversation.DeleteConversationConfig{}
})
nodes.RegisterNodeAdaptor(entity.NodeTypeConversationList, func() nodes.NodeAdaptor {
return &conversation.ConversationListConfig{}
})
nodes.RegisterNodeAdaptor(entity.NodeTypeConversationHistory, func() nodes.NodeAdaptor {
return &conversation.ConversationHistoryConfig{}
})
nodes.RegisterNodeAdaptor(entity.NodeTypeClearConversationHistory, func() nodes.NodeAdaptor {
return &conversation.ClearConversationHistoryConfig{}
})
nodes.RegisterNodeAdaptor(entity.NodeTypeMessageList, func() nodes.NodeAdaptor {
return &conversation.MessageListConfig{}
})
nodes.RegisterNodeAdaptor(entity.NodeTypeCreateMessage, func() nodes.NodeAdaptor {
return &conversation.CreateMessageConfig{}
})
nodes.RegisterNodeAdaptor(entity.NodeTypeEditMessage, func() nodes.NodeAdaptor {
return &conversation.EditMessageConfig{}
})
nodes.RegisterNodeAdaptor(entity.NodeTypeDeleteMessage, func() nodes.NodeAdaptor {
return &conversation.DeleteMessageConfig{}
})
// register branch adaptors
nodes.RegisterBranchAdaptor(entity.NodeTypeSelector, func() nodes.BranchAdaptor {

View File

@@ -0,0 +1,93 @@
{
"nodes": [
{
"id": "100001",
"type": "1",
"meta": {
"position": {
"x": 13.818572856225469,
"y": -37.20384999753011
}
},
"data": {
"nodeMeta": {
"title": "开始",
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
"subTitle": ""
},
"settings": null,
"version": "",
"outputs": [
{
"type": "string",
"name": "USER_INPUT",
"required": false
},
{
"type": "string",
"name": "CONVERSATION_NAME",
"required": false,
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
"defaultValue": "Default"
},
{
"type": "string",
"name": "input",
"required": false
}
],
"trigger_parameters": []
}
},
{
"id": "900001",
"type": "2",
"meta": {
"position": {
"x": 642.9671427865745,
"y": -37.20384999753011
}
},
"data": {
"nodeMeta": {
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
"subTitle": "",
"title": "结束"
},
"inputs": {
"terminatePlan": "returnVariables",
"inputParameters": [
{
"name": "output",
"input": {
"type": "string",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "100001",
"name": "input"
},
"rawMeta": {
"type": 1
}
}
}
}
]
}
}
}
],
"edges": [
{
"sourceNodeID": "100001",
"targetNodeID": "900001"
}
],
"versions": {
"loop": "v2"
}
}

View File

@@ -0,0 +1,89 @@
{
"nodes": [{
"blocks": [],
"data": {
"nodeMeta": {
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
"subTitle": "",
"title": "开始"
},
"outputs": [{
"name": "USER_INPUT",
"required": false,
"type": "string"
}, {
"defaultValue": "Default",
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
"name": "CONVERSATION_NAME",
"required": false,
"type": "string"
}],
"trigger_parameters": []
},
"edges": null,
"id": "100001",
"meta": {
"position": {
"x": 0,
"y": 0
}
},
"type": "1"
}, {
"blocks": [],
"data": {
"inputs": {
"content": {
"type": "string",
"value": {
"content": "{{output}}",
"type": "literal"
}
},
"inputParameters": [{
"input": {
"type": "string",
"value": {
"content": {
"blockID": "100001",
"name": "USER_INPUT",
"source": "block-output"
},
"rawMeta": {
"type": 1
},
"type": "ref"
}
},
"name": "output"
}],
"streamingOutput": true,
"terminatePlan": "useAnswerContent"
},
"nodeMeta": {
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
"subTitle": "",
"title": "结束"
}
},
"edges": null,
"id": "900001",
"meta": {
"position": {
"x": 1000,
"y": 0
}
},
"type": "2"
}],
"edges": [{
"sourceNodeID": "100001",
"targetNodeID": "900001",
"sourcePortID": ""
}],
"versions": {
"loop": "v2"
}
}

View File

@@ -0,0 +1,193 @@
{
"nodes": [{
"blocks": [],
"data": {
"nodeMeta": {
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
"subTitle": "",
"title": "开始"
},
"outputs": [{
"name": "USER_INPUT",
"required": false,
"type": "string"
}, {
"defaultValue": "Default",
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
"name": "CONVERSATION_NAME",
"required": false,
"type": "string"
}],
"trigger_parameters": []
},
"edges": null,
"id": "100001",
"meta": {
"position": {
"x": 0,
"y": 0
}
},
"type": "1"
}, {
"blocks": [],
"data": {
"inputs": {
"content": {
"type": "string",
"value": {
"content": "{{output}}",
"type": "literal"
}
},
"inputParameters": [{
"input": {
"schema": {
"schema": [{
"name": "conversationName",
"type": "string"
}, {
"name": "conversationId",
"type": "string"
}],
"type": "object"
},
"type": "list",
"value": {
"content": {
"blockID": "107363",
"name": "conversationList",
"source": "block-output"
},
"rawMeta": {
"type": 103
},
"type": "ref"
}
},
"name": "output"
}],
"streamingOutput": true,
"terminatePlan": "useAnswerContent"
},
"nodeMeta": {
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
"subTitle": "",
"title": "结束"
}
},
"edges": null,
"id": "900001",
"meta": {
"position": {
"x": 1058,
"y": -13
}
},
"type": "2"
}, {
"blocks": [],
"data": {
"inputs": {
"inputParameters": []
},
"nodeMeta": {
"description": "用于查询所有会话,包含静态会话、动态会话",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-查询会话.jpg",
"mainColor": "#F2B600",
"subTitle": "查询会话列表",
"title": "查询会话列表"
},
"outputs": [{
"name": "conversationList",
"schema": {
"schema": [{
"name": "conversationName",
"type": "string"
}, {
"name": "conversationId",
"type": "string"
}],
"type": "object"
},
"type": "list"
}]
},
"edges": null,
"id": "107363",
"meta": {
"position": {
"x": 561,
"y": 186
}
},
"type": "53"
}, {
"blocks": [],
"data": {
"inputs": {
"inputParameters": [{
"input": {
"type": "string",
"value": {
"content": {
"blockID": "100001",
"name": "CONVERSATION_NAME",
"source": "block-output"
},
"rawMeta": {
"type": 1
},
"type": "ref"
}
},
"name": "conversationName"
}]
},
"nodeMeta": {
"description": "用于创建会话",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
"mainColor": "#F2B600",
"subTitle": "创建会话",
"title": "创建会话"
},
"outputs": [{
"name": "isSuccess",
"type": "boolean"
}, {
"name": "isExisted",
"type": "boolean"
}, {
"name": "conversationId",
"type": "string"
}]
},
"edges": null,
"id": "110245",
"meta": {
"position": {
"x": 487,
"y": -196
}
},
"type": "39"
}],
"edges": [{
"sourceNodeID": "100001",
"targetNodeID": "110245",
"sourcePortID": ""
}, {
"sourceNodeID": "107363",
"targetNodeID": "900001",
"sourcePortID": ""
}, {
"sourceNodeID": "110245",
"targetNodeID": "107363",
"sourcePortID": ""
}],
"versions": {
"loop": "v2"
}
}

View File

@@ -0,0 +1,137 @@
{
"nodes": [
{
"id": "100001",
"type": "1",
"meta": {
"position": {
"x": 180,
"y": 13.700000000000003
}
},
"data": {
"nodeMeta": {
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
"subTitle": "",
"title": "开始"
},
"outputs": [
{
"type": "string",
"name": "input",
"required": false
}
],
"trigger_parameters": []
}
},
{
"id": "900001",
"type": "2",
"meta": {
"position": {
"x": 1100,
"y": 0.7000000000000028
}
},
"data": {
"nodeMeta": {
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
"subTitle": "",
"title": "结束"
},
"inputs": {
"terminatePlan": "returnVariables",
"inputParameters": [
{
"name": "output",
"input": {
"type": "string",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "163698",
"name": "conversationId"
},
"rawMeta": {
"type": 1
}
}
}
}
]
}
}
},
{
"id": "163698",
"type": "39",
"meta": {
"position": {
"x": 640,
"y": 0
}
},
"data": {
"outputs": [
{
"type": "boolean",
"name": "isSuccess"
},
{
"type": "boolean",
"name": "isExisted"
},
{
"type": "string",
"name": "conversationId"
}
],
"nodeMeta": {
"title": "创建会话",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
"description": "用于创建会话",
"mainColor": "#F2B600",
"subTitle": "创建会话"
},
"inputs": {
"inputParameters": [
{
"name": "conversationName",
"input": {
"type": "string",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "100001",
"name": "input"
},
"rawMeta": {
"type": 1
}
}
}
}
]
}
}
}
],
"edges": [
{
"sourceNodeID": "100001",
"targetNodeID": "163698"
},
{
"sourceNodeID": "163698",
"targetNodeID": "900001"
}
],
"versions": {
"loop": "v2"
}
}

View File

@@ -0,0 +1,129 @@
{
"nodes": [
{
"id": "100001",
"type": "1",
"meta": {
"position": {
"x": -13.523809523809522,
"y": -25.294372294372295
}
},
"data": {
"nodeMeta": {
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
"subTitle": "",
"title": "开始"
},
"outputs": [
{
"type": "string",
"name": "input",
"required": false
}
],
"trigger_parameters": []
}
},
{
"id": "900001",
"type": "2",
"meta": {
"position": {
"x": 890.3549783549786,
"y": -71.48917748917748
}
},
"data": {
"nodeMeta": {
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
"subTitle": "",
"title": "结束"
},
"inputs": {
"terminatePlan": "returnVariables",
"inputParameters": [
{
"name": "output",
"input": {
"type": "boolean",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "118024",
"name": "isSuccess"
},
"rawMeta": {
"type": 3
}
}
}
}
]
}
}
},
{
"id": "118024",
"type": "52",
"meta": {
"position": {
"x": 423.6623376623378,
"y": -126.39999999999999
}
},
"data": {
"outputs": [
{
"type": "boolean",
"name": "isSuccess"
}
],
"nodeMeta": {
"title": "删除会话",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-删除会话.jpg",
"description": "用于删除会话",
"mainColor": "#F2B600",
"subTitle": "删除会话"
},
"inputs": {
"inputParameters": [
{
"name": "conversationName",
"input": {
"type": "string",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "100001",
"name": "input"
},
"rawMeta": {
"type": 1
}
}
}
}
]
}
}
}
],
"edges": [
{
"sourceNodeID": "100001",
"targetNodeID": "118024"
},
{
"sourceNodeID": "118024",
"targetNodeID": "900001"
}
],
"versions": {
"loop": "v2"
}
}

View File

@@ -0,0 +1,191 @@
{
"nodes": [
{
"id": "100001",
"type": "1",
"meta": {
"position": {
"x": -243.67931247880136,
"y": -233.598184501318
}
},
"data": {
"nodeMeta": {
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
"subTitle": "",
"title": "开始"
},
"outputs": [
{
"type": "string",
"name": "input",
"required": false
}
],
"trigger_parameters": []
}
},
{
"id": "900001",
"type": "2",
"meta": {
"position": {
"x": 911.2952705396514,
"y": -331.2250749763467
}
},
"data": {
"nodeMeta": {
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
"subTitle": "",
"title": "结束"
},
"inputs": {
"terminatePlan": "returnVariables",
"inputParameters": [
{
"name": "output",
"input": {
"value": {
"type": "object_ref"
},
"type": "object",
"schema": [
{
"name": "isSuccess",
"input": {
"type": "boolean",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "122336",
"name": "isSuccess"
},
"rawMeta": {
"type": 3
}
}
}
},
{
"name": "isExisted",
"input": {
"type": "boolean",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "122336",
"name": "isExisted"
},
"rawMeta": {
"type": 3
}
}
}
},
{
"name": "conversationId",
"input": {
"type": "string",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "122336",
"name": "conversationId"
},
"rawMeta": {
"type": 1
}
}
}
}
]
}
}
]
}
}
},
{
"id": "122336",
"type": "51",
"meta": {
"position": {
"x": 343.08704991877585,
"y": -462.38794621339696
}
},
"data": {
"outputs": [
{
"type": "boolean",
"name": "isSuccess"
},
{
"type": "boolean",
"name": "isExisted"
},
{
"type": "string",
"name": "conversationId"
}
],
"nodeMeta": {
"title": "修改会话",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-编辑会话.jpg",
"description": "用于修改会话的名字",
"mainColor": "#F2B600",
"subTitle": "修改会话"
},
"inputs": {
"inputParameters": [
{
"name": "conversationName",
"input": {
"type": "string",
"value": {
"type": "literal",
"content": "template_v1",
"rawMeta": {
"type": 1
}
}
}
},
{
"name": "newConversationName",
"input": {
"type": "string",
"value": {
"type": "literal",
"content": "new",
"rawMeta": {
"type": 1
}
}
}
}
]
}
}
}
],
"edges": [
{
"sourceNodeID": "100001",
"targetNodeID": "122336"
},
{
"sourceNodeID": "122336",
"targetNodeID": "900001"
}
],
"versions": {
"loop": "v2"
}
}

View File

@@ -0,0 +1,262 @@
{
"nodes": [
{
"id": "100001",
"type": "1",
"meta": {
"position": {
"x": 180,
"y": 13.700000000000003
}
},
"data": {
"nodeMeta": {
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
"subTitle": "",
"title": "开始"
},
"outputs": [
{
"type": "string",
"name": "input",
"required": true
},
{
"type": "string",
"name": "new_name",
"required": true
}
],
"trigger_parameters": []
}
},
{
"id": "900001",
"type": "2",
"meta": {
"position": {
"x": 1560,
"y": 0.7000000000000028
}
},
"data": {
"nodeMeta": {
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
"subTitle": "",
"title": "结束"
},
"inputs": {
"terminatePlan": "returnVariables",
"inputParameters": [
{
"name": "obj",
"input": {
"value": {
"type": "object_ref"
},
"type": "object",
"schema": [
{
"name": "isSuccess",
"input": {
"type": "boolean",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "193175",
"name": "isSuccess"
},
"rawMeta": {
"type": 3
}
}
}
},
{
"name": "isExisted",
"input": {
"type": "boolean",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "193175",
"name": "isExisted"
},
"rawMeta": {
"type": 3
}
}
}
},
{
"name": "conversationId",
"input": {
"type": "string",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "193175",
"name": "conversationId"
},
"rawMeta": {
"type": 1
}
}
}
}
]
}
}
]
}
}
},
{
"id": "139551",
"type": "39",
"meta": {
"position": {
"x": 627.929589270746,
"y": -36.21123218776195
}
},
"data": {
"outputs": [
{
"type": "boolean",
"name": "isSuccess"
},
{
"type": "boolean",
"name": "isExisted"
},
{
"type": "string",
"name": "conversationId"
}
],
"nodeMeta": {
"title": "创建会话",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
"description": "用于创建会话",
"mainColor": "#F2B600",
"subTitle": "创建会话"
},
"inputs": {
"inputParameters": [
{
"name": "conversationName",
"input": {
"type": "string",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "100001",
"name": "input"
},
"rawMeta": {
"type": 1
}
}
}
}
]
}
}
},
{
"id": "193175",
"type": "51",
"meta": {
"position": {
"x": 1100,
"y": 0
}
},
"data": {
"outputs": [
{
"type": "boolean",
"name": "isSuccess"
},
{
"type": "boolean",
"name": "isExisted"
},
{
"type": "string",
"name": "conversationId"
}
],
"nodeMeta": {
"title": "修改会话",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-编辑会话.jpg",
"description": "用于修改会话的名字",
"mainColor": "#F2B600",
"subTitle": "修改会话"
},
"inputs": {
"inputParameters": [
{
"name": "conversationName",
"input": {
"type": "string",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "100001",
"name": "input"
},
"rawMeta": {
"type": 1
}
}
}
},
{
"name": "newConversationName",
"input": {
"type": "string",
"value": {
"type": "ref",
"content": {
"source": "block-output",
"blockID": "100001",
"name": "new_name"
},
"rawMeta": {
"type": 1
}
}
}
}
]
}
}
}
],
"edges": [
{
"sourceNodeID": "100001",
"targetNodeID": "139551"
},
{
"sourceNodeID": "193175",
"targetNodeID": "900001"
},
{
"sourceNodeID": "139551",
"targetNodeID": "193175"
}
],
"versions": {
"loop": "v2"
}
}

View File

@@ -0,0 +1,234 @@
{
"nodes": [{
"blocks": [],
"data": {
"nodeMeta": {
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
"subTitle": "",
"title": "开始"
},
"outputs": [{
"name": "USER_INPUT",
"required": false,
"type": "string"
}, {
"defaultValue": "Default",
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
"name": "CONVERSATION_NAME",
"required": false,
"type": "string"
}],
"trigger_parameters": []
},
"edges": null,
"id": "100001",
"meta": {
"position": {
"x": 0,
"y": 0
}
},
"type": "1"
}, {
"blocks": [],
"data": {
"inputs": {
"inputParameters": [{
"input": {
"type": "boolean",
"value": {
"content": {
"blockID": "195185",
"name": "isSuccess",
"source": "block-output"
},
"rawMeta": {
"type": 3
},
"type": "ref"
}
},
"name": "output"
}, {
"input": {
"type": "string",
"value": {
"content": {
"blockID": "195185",
"name": "message.messageId",
"source": "block-output"
},
"rawMeta": {
"type": 1
},
"type": "ref"
}
},
"name": "mID"
}],
"terminatePlan": "returnVariables"
},
"nodeMeta": {
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
"subTitle": "",
"title": "结束"
}
},
"edges": null,
"id": "900001",
"meta": {
"position": {
"x": 1000,
"y": 0
}
},
"type": "2"
}, {
"blocks": [],
"data": {
"inputs": {
"inputParameters": [{
"input": {
"type": "string",
"value": {
"content": {
"blockID": "100001",
"name": "CONVERSATION_NAME",
"source": "block-output"
},
"rawMeta": {
"type": 1
},
"type": "ref"
}
},
"name": "conversationName"
}, {
"input": {
"type": "string",
"value": {
"content": "user",
"type": "literal"
}
},
"name": "role"
}, {
"input": {
"type": "string",
"value": {
"content": "1",
"rawMeta": {
"type": 1
},
"type": "literal"
}
},
"name": "content"
}]
},
"nodeMeta": {
"description": "用于创建消息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-创建消息.jpg",
"mainColor": "#F2B600",
"subTitle": "创建消息",
"title": "创建消息"
},
"outputs": [{
"name": "isSuccess",
"type": "boolean"
}, {
"name": "message",
"schema": [{
"name": "messageId",
"type": "string"
}, {
"name": "role",
"type": "string"
}, {
"name": "contentType",
"type": "string"
}, {
"name": "content",
"type": "string"
}],
"type": "object"
}]
},
"edges": null,
"id": "195185",
"meta": {
"position": {
"x": 482,
"y": -13
}
},
"type": "55"
}, {
"blocks": [],
"data": {
"inputs": {
"inputParameters": [{
"input": {
"type": "string",
"value": {
"content": {
"blockID": "100001",
"name": "CONVERSATION_NAME",
"source": "block-output"
},
"rawMeta": {
"type": 1
},
"type": "ref"
}
},
"name": "conversationName"
}]
},
"nodeMeta": {
"description": "用于创建会话",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
"mainColor": "#F2B600",
"subTitle": "创建会话",
"title": "创建会话"
},
"outputs": [{
"name": "isSuccess",
"type": "boolean"
}, {
"name": "isExisted",
"type": "boolean"
}, {
"name": "conversationId",
"type": "string"
}]
},
"edges": null,
"id": "121849",
"meta": {
"position": {
"x": 302,
"y": -236
}
},
"type": "39"
}],
"edges": [{
"sourceNodeID": "100001",
"targetNodeID": "121849",
"sourcePortID": ""
}, {
"sourceNodeID": "195185",
"targetNodeID": "900001",
"sourcePortID": ""
}, {
"sourceNodeID": "121849",
"targetNodeID": "195185",
"sourcePortID": ""
}],
"versions": {
"loop": "v2"
}
}

View File

@@ -0,0 +1,310 @@
{
"nodes": [{
"blocks": [],
"data": {
"nodeMeta": {
"description": "工作流的起始节点,用于设定启动工作流需要的信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Start-v2.jpg",
"subTitle": "",
"title": "开始"
},
"outputs": [{
"name": "USER_INPUT",
"required": false,
"type": "string"
}, {
"defaultValue": "Default",
"description": "本次请求绑定的会话,会自动写入消息、会从该会话读对话历史。",
"name": "CONVERSATION_NAME",
"required": false,
"type": "string"
}],
"trigger_parameters": []
},
"edges": null,
"id": "100001",
"meta": {
"position": {
"x": 0,
"y": 0
}
},
"type": "1"
}, {
"blocks": [],
"data": {
"inputs": {
"inputParameters": [{
"input": {
"schema": {
"schema": [{
"name": "messageId",
"type": "string"
}, {
"name": "role",
"type": "string"
}, {
"name": "contentType",
"type": "string"
}, {
"name": "content",
"type": "string"
}],
"type": "object"
},
"type": "list",
"value": {
"content": {
"blockID": "132703",
"name": "messageList",
"source": "block-output"
},
"rawMeta": {
"type": 103
},
"type": "ref"
}
},
"name": "output"
}],
"terminatePlan": "returnVariables"
},
"nodeMeta": {
"description": "工作流的最终节点,用于返回工作流运行后的结果信息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-End-v2.jpg",
"subTitle": "",
"title": "结束"
}
},
"edges": null,
"id": "900001",
"meta": {
"position": {
"x": 1000,
"y": 0
}
},
"type": "2"
}, {
"blocks": [],
"data": {
"inputs": {
"inputParameters": [{
"input": {
"type": "string",
"value": {
"content": {
"blockID": "100001",
"name": "CONVERSATION_NAME",
"source": "block-output"
},
"rawMeta": {
"type": 1
},
"type": "ref"
}
},
"name": "conversationName"
}]
},
"nodeMeta": {
"description": "用于查询消息列表",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-List.jpeg",
"mainColor": "#F2B600",
"subTitle": "查询消息列表",
"title": "查询消息列表"
},
"outputs": [{
"name": "messageList",
"schema": {
"schema": [{
"name": "messageId",
"type": "string"
}, {
"name": "role",
"type": "string"
}, {
"name": "contentType",
"type": "string"
}, {
"name": "content",
"type": "string"
}],
"type": "object"
},
"type": "list"
}, {
"name": "firstId",
"type": "string"
}, {
"name": "lastId",
"type": "string"
}, {
"name": "hasMore",
"type": "boolean"
}]
},
"edges": null,
"id": "132703",
"meta": {
"position": {
"x": 514,
"y": 96
}
},
"type": "37"
}, {
"blocks": [],
"data": {
"inputs": {
"inputParameters": [{
"input": {
"type": "string",
"value": {
"content": {
"blockID": "100001",
"name": "CONVERSATION_NAME",
"source": "block-output"
},
"rawMeta": {
"type": 1
},
"type": "ref"
}
},
"name": "conversationName"
}]
},
"nodeMeta": {
"description": "用于创建会话",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Conversation-Create.jpeg",
"mainColor": "#F2B600",
"subTitle": "创建会话",
"title": "创建会话"
},
"outputs": [{
"name": "isSuccess",
"type": "boolean"
}, {
"name": "isExisted",
"type": "boolean"
}, {
"name": "conversationId",
"type": "string"
}]
},
"edges": null,
"id": "166724",
"meta": {
"position": {
"x": 323,
"y": -332
}
},
"type": "39"
}, {
"blocks": [],
"data": {
"inputs": {
"inputParameters": [{
"input": {
"type": "string",
"value": {
"content": {
"blockID": "100001",
"name": "CONVERSATION_NAME",
"source": "block-output"
},
"rawMeta": {
"type": 1
},
"type": "ref"
}
},
"name": "conversationName"
}, {
"input": {
"type": "string",
"value": {
"content": "user",
"type": "literal"
}
},
"name": "role"
}, {
"input": {
"type": "string",
"value": {
"content": {
"blockID": "100001",
"name": "USER_INPUT",
"source": "block-output"
},
"rawMeta": {
"type": 1
},
"type": "ref"
}
},
"name": "content"
}]
},
"nodeMeta": {
"description": "用于创建消息",
"icon": "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-创建消息.jpg",
"mainColor": "#F2B600",
"subTitle": "创建消息",
"title": "创建消息"
},
"outputs": [{
"name": "isSuccess",
"type": "boolean"
}, {
"name": "message",
"schema": [{
"name": "messageId",
"type": "string"
}, {
"name": "role",
"type": "string"
}, {
"name": "contentType",
"type": "string"
}, {
"name": "content",
"type": "string"
}],
"type": "object"
}]
},
"edges": null,
"id": "157061",
"meta": {
"position": {
"x": 479,
"y": -127
}
},
"type": "55"
}],
"edges": [{
"sourceNodeID": "100001",
"targetNodeID": "166724",
"sourcePortID": ""
}, {
"sourceNodeID": "132703",
"targetNodeID": "900001",
"sourcePortID": ""
}, {
"sourceNodeID": "157061",
"targetNodeID": "132703",
"sourcePortID": ""
}, {
"sourceNodeID": "166724",
"targetNodeID": "157061",
"sourcePortID": ""
}],
"versions": {
"loop": "v2"
}
}

View File

@@ -19,6 +19,7 @@ package validate
import (
"context"
"fmt"
"regexp"
"strconv"
@@ -29,6 +30,7 @@ import (
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"github.com/coze-dev/coze-studio/backend/domain/workflow/variable"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
@@ -390,10 +392,13 @@ func (cv *CanvasValidator) CheckSubWorkFlowTerminatePlanType(ctx context.Context
if len(subID2SubVersion) > 0 {
for id, version := range subID2SubVersion {
v, err := workflow.GetRepository().GetVersion(ctx, id, version)
v, existed, err := workflow.GetRepository().GetVersion(ctx, id, version)
if err != nil {
return nil, err
}
if !existed {
return nil, vo.WrapError(errno.ErrWorkflowNotFound, fmt.Errorf("workflow version %s not found for ID %d: %w", version, id, err), errorx.KV("id", strconv.FormatInt(id, 10)))
}
var canvas vo.Canvas
if err = sonic.UnmarshalString(v.Canvas, &canvas); err != nil {

View File

@@ -28,6 +28,7 @@ import (
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
workflow2 "github.com/coze-dev/coze-studio/backend/api/model/workflow"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
@@ -87,6 +88,11 @@ func init() {
_ = compose.RegisterSerializableType[workflowModel.Locator]("wf_locator")
_ = compose.RegisterSerializableType[workflowModel.BizType]("biz_type")
_ = compose.RegisterSerializableType[*execute.AppVariables]("app_variables")
_ = compose.RegisterSerializableType[workflow2.WorkflowMode]("workflow_mode")
_ = compose.RegisterSerializableType[*schema.Message]("schema_message")
_ = compose.RegisterSerializableType[*crossmessage.WfMessage]("history_messages")
_ = compose.RegisterSerializableType[*crossmessage.Content]("content")
}
func (s *State) AddQuestion(nodeKey vo.NodeKey, question *qa.Question) {

View File

@@ -31,6 +31,8 @@ import (
model2 "github.com/cloudwego/eino/components/model"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/schema"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
@@ -98,6 +100,14 @@ func TestLLM(t *testing.T) {
ctx := ctxcache.Init(context.Background())
defer mockey.Mock(execute.GetExeCtx).Return(&execute.Context{
RootCtx: execute.RootCtx{
ExeCfg: workflowModel.ExecuteConfig{
WorkflowMode: 0,
},
},
NodeCtx: &execute.NodeCtx{},
}).Build().UnPatch()
t.Run("plain text output, non-streaming mode", func(t *testing.T) {
if openaiModel == nil {
defer func() {

View File

@@ -98,13 +98,24 @@ func TestQuestionAnswer(t *testing.T) {
defer s.Close()
redisClient := redis.NewWithAddrAndPassword(s.Addr(), "")
var oneChatModel = chatModel
if oneChatModel == nil {
oneChatModel = &testutil.UTChatModel{
InvokeResultProvider: func(_ int, in []*schema.Message) (*schema.Message, error) {
return &schema.Message{
Role: schema.Assistant,
Content: "-1",
}, nil
},
}
}
mockIDGen := mock.NewMockIDGenerator(ctrl)
mockIDGen.EXPECT().GenID(gomock.Any()).Return(time.Now().UnixNano(), nil).AnyTimes()
mockTos := storageMock.NewMockStorage(ctrl)
mockTos.EXPECT().GetObjectUrl(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil).AnyTimes()
repo := repo2.NewRepository(mockIDGen, db, redisClient, mockTos,
checkpoint.NewRedisStore(redisClient), nil, nil)
repo, _ := repo2.NewRepository(mockIDGen, db, redisClient, mockTos,
checkpoint.NewRedisStore(redisClient), oneChatModel, nil)
mockey.Mock(workflow.GetRepository).Return(repo).Build()
t.Run("answer directly, no structured output", func(t *testing.T) {

View File

@@ -380,7 +380,7 @@ func handleEvent(ctx context.Context, event *Event, repo workflow.Repository,
}
if updatedRows, currentStatus, err = repo.UpdateWorkflowExecution(ctx, wfExec, []entity.WorkflowExecuteStatus{entity.WorkflowRunning,
entity.WorkflowInterrupted}); err != nil {
entity.WorkflowInterrupted, entity.WorkflowCancel}); err != nil {
return noTerminate, fmt.Errorf("failed to save workflow execution when canceled: %v", err)
} else if updatedRows == 0 {
return noTerminate, fmt.Errorf("failed to update workflow execution to canceled for execution id %d, current status is %v", exeID, currentStatus)

View File

@@ -0,0 +1,141 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conversation
import (
"context"
"errors"
"fmt"
"sync/atomic"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
crossconversation "github.com/coze-dev/coze-studio/backend/crossdomain/contract/conversation"
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"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/ternary"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type ClearConversationHistoryConfig struct{}
type ClearConversationHistory struct{}
func (c *ClearConversationHistoryConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
ns := &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeClearConversationHistory,
Name: n.Data.Meta.Title,
Configs: c,
}
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
return nil, err
}
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
return nil, err
}
return ns, nil
}
func (c *ClearConversationHistoryConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
return &ClearConversationHistory{}, nil
}
func (c *ClearConversationHistory) Invoke(ctx context.Context, in map[string]any) (map[string]any, error) {
var (
execCtx = execute.GetExeCtx(ctx)
env = ternary.IFElse(execCtx.ExeCfg.Mode == workflowModel.ExecuteModeRelease, vo.Online, vo.Draft)
appID = execCtx.ExeCfg.AppID
agentID = execCtx.ExeCfg.AgentID
connectorID = execCtx.ExeCfg.ConnectorID
userID = execCtx.ExeCfg.Operator
version = execCtx.ExeCfg.Version
)
if agentID != nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, query conversation list is not available"))
}
if appID == nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("query conversation list node, app id is required"))
}
conversationName, ok := in["conversationName"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversation name is required"))
}
t, existed, err := wf.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: appID,
Name: ptr.Of(conversationName),
Version: ptr.Of(version),
})
if err != nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
var conversationID int64
if existed {
ret, existed, err := wf.GetRepository().GetStaticConversationByTemplateID(ctx, env, userID, connectorID, t.TemplateID)
if err != nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if existed {
conversationID = ret.ConversationID
}
} else {
ret, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
if err != nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if existed {
conversationID = ret.ConversationID
}
}
if !existed {
return map[string]any{
"isSuccess": false,
}, nil
}
resp, err := crossconversation.DefaultSVC().ClearConversationHistory(ctx, &crossconversation.ClearConversationHistoryReq{
ConversationID: conversationID,
})
if err != nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if resp == nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, fmt.Errorf("clear conversation history failed, response is nil"))
}
if execCtx.ExeCfg.SectionID != nil {
atomic.StoreInt64(execCtx.ExeCfg.SectionID, resp.SectionID)
}
return map[string]any{
"isSuccess": true,
}, nil
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conversation
import (
"context"
"errors"
"fmt"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
crossconversation "github.com/coze-dev/coze-studio/backend/crossdomain/contract/conversation"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"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/ternary"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type ConversationHistoryConfig struct{}
type ConversationHistory struct{}
func (ch *ConversationHistoryConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
ns := &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeConversationHistory,
Name: n.Data.Meta.Title,
Configs: ch,
}
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
return nil, err
}
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
return nil, err
}
return ns, nil
}
func (ch *ConversationHistoryConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
return &ConversationHistory{}, nil
}
func (ch *ConversationHistory) Invoke(ctx context.Context, input map[string]any) (map[string]any, error) {
var (
execCtx = execute.GetExeCtx(ctx)
env = ternary.IFElse(execCtx.ExeCfg.Mode == workflowModel.ExecuteModeRelease, vo.Online, vo.Draft)
appID = execCtx.ExeCfg.AppID
agentID = execCtx.ExeCfg.AgentID
connectorID = execCtx.ExeCfg.ConnectorID
userID = execCtx.ExeCfg.Operator
version = execCtx.ExeCfg.Version
initRunID = execCtx.ExeCfg.InitRoundID
)
if agentID != nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, query conversation list is not available"))
}
if appID == nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("query conversation list node, app id is required"))
}
conversationName, ok := input["conversationName"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversation name is required"))
}
rounds, ok := input["rounds"].(int64)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("rounds is required"))
}
template, existed, err := wf.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: appID,
Name: ptr.Of(conversationName),
Version: ptr.Of(version),
})
if err != nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
var conversationID int64
if existed {
var sc *entity.StaticConversation
sc, existed, err = wf.GetRepository().GetStaticConversationByTemplateID(ctx, env, userID, connectorID, template.TemplateID)
if err != nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if existed {
conversationID = sc.ConversationID
}
} else {
var dc *entity.DynamicConversation
dc, existed, err = wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
if err != nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if existed {
conversationID = dc.ConversationID
}
}
if !existed {
return nil, vo.WrapError(errno.ErrConversationOfAppNotFound, fmt.Errorf("the conversation name does not exist: '%v'", conversationName))
}
currentConversationID := execCtx.ExeCfg.ConversationID
isCurrentConversation := currentConversationID != nil && *currentConversationID == conversationID
var sectionID int64
if isCurrentConversation {
if execCtx.ExeCfg.SectionID == nil {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("section id is required"))
}
sectionID = *execCtx.ExeCfg.SectionID
} else {
cInfo, err := crossconversation.DefaultSVC().GetByID(ctx, conversationID)
if err != nil {
return nil, err
}
sectionID = cInfo.SectionID
}
runIDs, err := crossmessage.DefaultSVC().GetLatestRunIDs(ctx, &crossmessage.GetLatestRunIDsRequest{
ConversationID: conversationID,
UserID: userID,
AppID: *appID,
Rounds: rounds,
InitRunID: initRunID,
SectionID: sectionID,
})
if err != nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if len(runIDs) == 0 {
return map[string]any{
"messageList": []any{},
}, nil
}
response, err := crossmessage.DefaultSVC().GetMessagesByRunIDs(ctx, &crossmessage.GetMessagesByRunIDsRequest{
ConversationID: conversationID,
RunIDs: runIDs,
})
if err != nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
var messageList []any
for _, msg := range response.Messages {
content, err := nodes.ConvertMessageToString(ctx, msg)
if err != nil {
return nil, vo.WrapError(errno.ErrConversationNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
messageList = append(messageList, map[string]any{
"role": string(msg.Role),
"content": content,
})
}
return map[string]any{
"messageList": messageList,
}, nil
}

View File

@@ -0,0 +1,153 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conversation
import (
"context"
"fmt"
"strconv"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type ConversationList struct{}
type ConversationListConfig struct{}
func (c *ConversationListConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
ns := &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeConversationList,
Name: n.Data.Meta.Title,
Configs: c,
}
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
return nil, err
}
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
return nil, err
}
return ns, nil
}
func (c *ConversationListConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
return &ConversationList{}, nil
}
type conversationInfo struct {
conversationName string
conversationId string
}
func (c *ConversationList) Invoke(ctx context.Context, _ map[string]any) (map[string]any, error) {
var (
execCtx = execute.GetExeCtx(ctx)
env = ternary.IFElse(execCtx.ExeCfg.Mode == workflowModel.ExecuteModeRelease, vo.Online, vo.Draft)
appID = execCtx.ExeCfg.AppID
agentID = execCtx.ExeCfg.AgentID
connectorID = execCtx.ExeCfg.ConnectorID
userID = execCtx.ExeCfg.Operator
version = execCtx.ExeCfg.Version
)
if agentID != nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, query conversation list is not available"))
}
if appID == nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("query conversation list node, app id is required"))
}
templates, err := workflow.GetRepository().ListConversationTemplate(ctx, env, &vo.ListConversationTemplatePolicy{
AppID: *appID,
Version: ptr.Of(version),
})
if err != nil {
return nil, err
}
templateIds := make([]int64, 0, len(templates))
for _, template := range templates {
templateIds = append(templateIds, template.TemplateID)
}
staticConversations, err := workflow.GetRepository().MGetStaticConversation(ctx, env, userID, connectorID, templateIds)
if err != nil {
return nil, err
}
templateIDToConvID := slices.ToMap(staticConversations, func(conv *entity.StaticConversation) (int64, int64) {
return conv.TemplateID, conv.ConversationID
})
var conversationList []conversationInfo
for _, template := range templates {
convID, ok := templateIDToConvID[template.TemplateID]
if !ok {
convID = 0
}
conversationList = append(conversationList, conversationInfo{
conversationName: template.Name,
conversationId: strconv.FormatInt(convID, 10),
})
}
dynamicConversations, err := workflow.GetRepository().ListDynamicConversation(ctx, env, &vo.ListConversationPolicy{
ListConversationMeta: vo.ListConversationMeta{
APPID: *appID,
UserID: userID,
ConnectorID: connectorID,
},
})
if err != nil {
return nil, err
}
for _, conv := range dynamicConversations {
conversationList = append(conversationList, conversationInfo{
conversationName: conv.Name,
conversationId: strconv.FormatInt(conv.ConversationID, 10),
})
}
resultList := make([]any, len(conversationList))
for i, v := range conversationList {
resultList[i] = map[string]any{
"conversationName": v.conversationName,
"conversationId": v.conversationId,
}
}
return map[string]any{
"conversationList": resultList,
}, nil
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conversation
import (
"context"
"errors"
"fmt"
"github.com/coze-dev/coze-studio/backend/api/model/conversation/common"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
crossconversation "github.com/coze-dev/coze-studio/backend/crossdomain/contract/conversation"
conventity "github.com/coze-dev/coze-studio/backend/domain/conversation/conversation/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type CreateConversationConfig struct{}
type CreateConversation struct{}
func (c *CreateConversationConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
ns := &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeCreateConversation,
Name: n.Data.Meta.Title,
Configs: c,
}
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
return nil, err
}
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
return nil, err
}
return ns, nil
}
func (c *CreateConversationConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
return &CreateConversation{}, nil
}
func (c *CreateConversation) Invoke(ctx context.Context, input map[string]any) (map[string]any, error) {
var (
execCtx = execute.GetExeCtx(ctx)
env = ternary.IFElse(execCtx.ExeCfg.Mode == workflowModel.ExecuteModeRelease, vo.Online, vo.Draft)
appID = execCtx.ExeCfg.AppID
agentID = execCtx.ExeCfg.AgentID
version = execCtx.ExeCfg.Version
connectorID = execCtx.ExeCfg.ConnectorID
userID = execCtx.ExeCfg.Operator
conversationIDGenerator = workflow.ConversationIDGenerator(func(ctx context.Context, appID int64, userID, connectorID int64) (*conventity.Conversation, error) {
return crossconversation.DefaultSVC().CreateConversation(ctx, &conventity.CreateMeta{
AgentID: appID,
UserID: userID,
ConnectorID: connectorID,
Scene: common.Scene_SceneWorkflow,
})
})
)
if agentID != nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, create conversation is not available"))
}
if appID == nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, errors.New("create conversation node, app id is required"))
}
conversationName, ok := input["conversationName"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversation name is required"))
}
template, existed, err := workflow.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: appID,
Name: ptr.Of(conversationName),
Version: ptr.Of(version),
})
if err != nil {
return nil, err
}
if existed {
cID, _, existed, err := workflow.GetRepository().GetOrCreateStaticConversation(ctx, env, conversationIDGenerator, &vo.CreateStaticConversation{
AppID: ptr.From(appID),
TemplateID: template.TemplateID,
UserID: userID,
ConnectorID: connectorID,
})
if err != nil {
return nil, err
}
return map[string]any{
"isSuccess": true,
"conversationId": cID,
"isExisted": existed,
}, nil
}
cID, _, existed, err := workflow.GetRepository().GetOrCreateDynamicConversation(ctx, env, conversationIDGenerator, &vo.CreateDynamicConversation{
AppID: ptr.From(appID),
UserID: userID,
ConnectorID: connectorID,
Name: conversationName,
})
if err != nil {
return nil, err
}
return map[string]any{
"isSuccess": true,
"conversationId": cID,
"isExisted": existed,
}, nil
}

View File

@@ -0,0 +1,299 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conversation
import (
"context"
"errors"
"fmt"
"github.com/coze-dev/coze-studio/backend/api/model/conversation/common"
conventity "github.com/coze-dev/coze-studio/backend/domain/conversation/conversation/entity"
"strconv"
"sync/atomic"
einoSchema "github.com/cloudwego/eino/schema"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
crossagentrun "github.com/coze-dev/coze-studio/backend/crossdomain/contract/agentrun"
crossconversation "github.com/coze-dev/coze-studio/backend/crossdomain/contract/conversation"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
agententity "github.com/coze-dev/coze-studio/backend/domain/conversation/agentrun/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type CreateMessageConfig struct{}
type CreateMessage struct{}
func (c *CreateMessageConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
ns := &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeCreateMessage,
Name: n.Data.Meta.Title,
Configs: c,
}
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
return nil, err
}
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
return nil, err
}
return ns, nil
}
func (c *CreateMessageConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
return &CreateMessage{}, nil
}
func (c *CreateMessage) getConversationIDByName(ctx context.Context, env vo.Env, appID *int64, version, conversationName string, userID, connectorID int64) (int64, error) {
template, isExist, err := workflow.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: appID,
Name: ptr.Of(conversationName),
Version: ptr.Of(version),
})
if err != nil {
return 0, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
conversationIDGenerator := workflow.ConversationIDGenerator(func(ctx context.Context, appID int64, userID, connectorID int64) (*conventity.Conversation, error) {
return crossconversation.DefaultSVC().CreateConversation(ctx, &conventity.CreateMeta{
AgentID: appID,
UserID: userID,
ConnectorID: connectorID,
Scene: common.Scene_SceneWorkflow,
})
})
var conversationID int64
if isExist {
cID, _, _, err := workflow.GetRepository().GetOrCreateStaticConversation(ctx, env, conversationIDGenerator, &vo.CreateStaticConversation{
AppID: ptr.From(appID),
TemplateID: template.TemplateID,
UserID: userID,
ConnectorID: connectorID,
})
if err != nil {
return 0, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
conversationID = cID
} else {
dc, _, err := workflow.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
if err != nil {
return 0, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if dc != nil {
conversationID = dc.ConversationID
}
}
return conversationID, nil
}
func (c *CreateMessage) Invoke(ctx context.Context, input map[string]any) (map[string]any, error) {
var (
execCtx = execute.GetExeCtx(ctx)
env = ternary.IFElse(execCtx.ExeCfg.Mode == workflowModel.ExecuteModeRelease, vo.Online, vo.Draft)
appID = execCtx.ExeCfg.AppID
agentID = execCtx.ExeCfg.AgentID
version = execCtx.ExeCfg.Version
connectorID = execCtx.ExeCfg.ConnectorID
userID = execCtx.ExeCfg.Operator
)
conversationName, ok := input["conversationName"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversationName is required"))
}
role, ok := input["role"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("role is required"))
}
if role != "user" && role != "assistant" {
return nil, vo.WrapError(errno.ErrInvalidParameter, fmt.Errorf("role must be user or assistant"))
}
content, ok := input["content"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("content is required"))
}
var conversationID int64
var err error
var resolvedAppID int64
if appID == nil {
if conversationName != "Default" {
return nil, vo.WrapError(errno.ErrOnlyDefaultConversationAllowInAgentScenario, errors.New("conversation node only allow in application"))
}
if agentID == nil || execCtx.ExeCfg.ConversationID == nil {
return map[string]any{
"isSuccess": false,
"message": map[string]any{
"messageId": "0",
"role": role,
"contentType": "text",
"content": content,
},
}, nil
}
conversationID = *execCtx.ExeCfg.ConversationID
resolvedAppID = *agentID
} else {
conversationID, err = c.getConversationIDByName(ctx, env, appID, version, conversationName, userID, connectorID)
if err != nil {
return nil, err
}
resolvedAppID = *appID
}
if conversationID == 0 {
return map[string]any{
"isSuccess": false,
"message": map[string]any{
"messageId": "0",
"role": role,
"contentType": "text",
"content": content,
},
}, nil
}
currentConversationID := execCtx.ExeCfg.ConversationID
isCurrentConversation := currentConversationID != nil && *currentConversationID == conversationID
var runID int64
var sectionID int64
if isCurrentConversation {
if execCtx.ExeCfg.SectionID != nil {
sectionID = *execCtx.ExeCfg.SectionID
} else {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("section id is required"))
}
} else {
cInfo, err := crossconversation.DefaultSVC().GetByID(ctx, conversationID)
if err != nil {
return nil, err
}
sectionID = cInfo.SectionID
}
if role == "user" {
// For user messages, always create a new run and store the ID in the context.
runRecord, err := crossagentrun.DefaultSVC().Create(ctx, &agententity.AgentRunMeta{
AgentID: resolvedAppID,
ConversationID: conversationID,
UserID: strconv.FormatInt(userID, 10),
ConnectorID: connectorID,
SectionID: sectionID,
})
if err != nil {
return nil, err
}
newRunID := runRecord.ID
if execCtx.ExeCfg.RoundID != nil {
atomic.StoreInt64(execCtx.ExeCfg.RoundID, newRunID)
}
runID = newRunID
} else if isCurrentConversation {
// For assistant messages in the same conversation, reuse the runID from the context.
if execCtx.ExeCfg.RoundID == nil {
// This indicates an inconsistent state, as a user message should have set this.
return map[string]any{
"isSuccess": false,
"message": map[string]any{
"messageId": "0",
"role": role,
"contentType": "text",
"content": content,
},
}, nil
}
runID = *execCtx.ExeCfg.RoundID
} else {
// For assistant messages in a different conversation or a new workflow run,
// find the latest runID or create a new one as a fallback.
runIDs, err := crossmessage.DefaultSVC().GetLatestRunIDs(ctx, &crossmessage.GetLatestRunIDsRequest{
ConversationID: conversationID,
UserID: userID,
AppID: resolvedAppID,
Rounds: 1,
})
if err != nil {
return nil, err
}
if len(runIDs) > 0 && runIDs[0] != 0 {
runID = runIDs[0]
} else {
runRecord, err := crossagentrun.DefaultSVC().Create(ctx, &agententity.AgentRunMeta{
AgentID: resolvedAppID,
ConversationID: conversationID,
UserID: strconv.FormatInt(userID, 10),
ConnectorID: connectorID,
SectionID: sectionID,
})
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
runID = runRecord.ID
}
}
message := &model.Message{
ConversationID: conversationID,
Role: einoSchema.RoleType(role),
Content: content,
ContentType: model.ContentType("text"),
UserID: strconv.FormatInt(userID, 10),
AgentID: resolvedAppID,
RunID: runID,
SectionID: sectionID,
}
if message.Role == einoSchema.User {
message.MessageType = model.MessageTypeQuestion
} else {
message.MessageType = model.MessageTypeAnswer
}
msg, err := crossmessage.DefaultSVC().Create(ctx, message)
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
messageOutput := map[string]any{
"messageId": msg.ID,
"role": role,
"contentType": "text",
"content": content,
}
return map[string]any{
"isSuccess": true,
"message": messageOutput,
}, nil
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conversation
import (
"context"
"errors"
"fmt"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type DeleteConversationConfig struct{}
type DeleteConversation struct{}
func (d *DeleteConversationConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
ns := &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeConversationDelete,
Name: n.Data.Meta.Title,
Configs: d,
}
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
return nil, err
}
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
return nil, err
}
return ns, nil
}
func (d *DeleteConversationConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
return &DeleteConversation{}, nil
}
func (d *DeleteConversation) Invoke(ctx context.Context, in map[string]any) (map[string]any, error) {
var (
execCtx = execute.GetExeCtx(ctx)
env = ternary.IFElse(execCtx.ExeCfg.Mode == workflowModel.ExecuteModeRelease, vo.Online, vo.Draft)
appID = execCtx.ExeCfg.AppID
agentID = execCtx.ExeCfg.AgentID
version = execCtx.ExeCfg.Version
connectorID = execCtx.ExeCfg.ConnectorID
userID = execCtx.ExeCfg.Operator
)
if agentID != nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, delete conversation is not available"))
}
if appID == nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, errors.New("delete conversation node, app id is required"))
}
cName, ok := in["conversationName"]
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversation name is required"))
}
conversationName := cName.(string)
_, existed, err := workflow.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: appID,
Name: ptr.Of(conversationName),
Version: ptr.Of(version),
})
if err != nil {
return nil, err
}
if existed {
return nil, vo.WrapError(errno.ErrConversationNodeInvalidOperation, fmt.Errorf("only conversation created through nodes are allowed to be modified or deleted"))
}
dyConversation, existed, err := workflow.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
if err != nil {
return nil, err
}
if !existed {
return nil, vo.WrapError(errno.ErrConversationOfAppNotFound, fmt.Errorf("the conversation name does not exist: '%v'", conversationName))
}
_, err = workflow.GetRepository().DeleteDynamicConversation(ctx, env, dyConversation.ID)
if err != nil {
return nil, err
}
return map[string]any{
"isSuccess": true,
}, nil
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conversation
import (
"context"
"errors"
"fmt"
"strconv"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
msgentity "github.com/coze-dev/coze-studio/backend/domain/conversation/message/entity"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type DeleteMessageConfig struct{}
type DeleteMessage struct{}
func (d *DeleteMessageConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
ns := &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeDeleteMessage,
Name: n.Data.Meta.Title,
Configs: d,
}
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
return nil, err
}
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
return nil, err
}
return ns, nil
}
func (d *DeleteMessageConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
return &DeleteMessage{}, nil
}
func (d *DeleteMessage) Invoke(ctx context.Context, input map[string]any) (map[string]any, error) {
var (
execCtx = execute.GetExeCtx(ctx)
env = ternary.IFElse(execCtx.ExeCfg.Mode == workflowModel.ExecuteModeRelease, vo.Online, vo.Draft)
appID = execCtx.ExeCfg.AppID
agentID = execCtx.ExeCfg.AgentID
version = execCtx.ExeCfg.Version
connectorID = execCtx.ExeCfg.ConnectorID
userID = execCtx.ExeCfg.Operator
successMap = map[string]any{
"isSuccess": true,
}
failedMap = map[string]any{
"isSuccess": false,
}
)
conversationName, ok := input["conversationName"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversationName is required"))
}
messageStr, ok := input["messageId"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("messageId is required"))
}
messageID, err := strconv.ParseInt(messageStr, 10, 64)
if err != nil {
return nil, vo.WrapError(errno.ErrInvalidParameter, err)
}
if appID == nil {
if conversationName != "Default" {
return nil, vo.WrapError(errno.ErrOnlyDefaultConversationAllowInAgentScenario, fmt.Errorf("only default conversation allow in agent scenario"))
}
if agentID == nil || execCtx.ExeCfg.ConversationID == nil {
return failedMap, nil
}
err = crossmessage.DefaultSVC().Delete(ctx, &msgentity.DeleteMeta{MessageIDs: []int64{messageID}, ConversationID: execCtx.ExeCfg.ConversationID})
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
return successMap, nil
}
t, existed, err := wf.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: appID,
Name: ptr.Of(conversationName),
Version: ptr.Of(version),
})
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if existed {
sc, existed, err := wf.GetRepository().GetStaticConversationByTemplateID(ctx, env, userID, connectorID, t.TemplateID)
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if !existed {
return failedMap, nil
}
err = crossmessage.DefaultSVC().Delete(ctx, &msgentity.DeleteMeta{MessageIDs: []int64{messageID}, ConversationID: ptr.Of(sc.ConversationID)})
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
return successMap, nil
} else {
dc, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if !existed {
return failedMap, nil
}
err = crossmessage.DefaultSVC().Delete(ctx, &msgentity.DeleteMeta{MessageIDs: []int64{messageID}, ConversationID: ptr.Of(dc.ConversationID)})
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
return successMap, nil
}
}

View File

@@ -0,0 +1,181 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conversation
import (
"context"
"errors"
"fmt"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
"strconv"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"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/ternary"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type EditMessageConfig struct{}
type EditMessage struct{}
func (e *EditMessageConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
ns := &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeEditMessage,
Name: n.Data.Meta.Title,
Configs: e,
}
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
return nil, err
}
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
return nil, err
}
return ns, nil
}
func (e *EditMessageConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
return &EditMessage{}, nil
}
func (e *EditMessage) Invoke(ctx context.Context, input map[string]any) (map[string]any, error) {
var (
execCtx = execute.GetExeCtx(ctx)
env = ternary.IFElse(execCtx.ExeCfg.Mode == workflowModel.ExecuteModeRelease, vo.Online, vo.Draft)
appID = execCtx.ExeCfg.AppID
agentID = execCtx.ExeCfg.AgentID
version = execCtx.ExeCfg.Version
connectorID = execCtx.ExeCfg.ConnectorID
userID = execCtx.ExeCfg.Operator
successMap = map[string]any{
"isSuccess": true,
}
failedMap = map[string]any{
"isSuccess": false,
}
)
conversationName, ok := input["conversationName"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversationName is required"))
}
messageStr, ok := input["messageId"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("messageId is required"))
}
messageID, err := strconv.ParseInt(messageStr, 10, 64)
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
newContent, ok := input["newContent"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("newContent is required"))
}
if appID == nil {
if conversationName != "Default" {
return nil, vo.WrapError(errno.ErrOnlyDefaultConversationAllowInAgentScenario, fmt.Errorf("only default conversation allow in agent scenario"))
}
if agentID == nil || execCtx.ExeCfg.ConversationID == nil {
return failedMap, nil
}
_, err = crossmessage.DefaultSVC().Edit(ctx, &model.Message{ConversationID: *execCtx.ExeCfg.ConversationID, ID: messageID, Content: newContent})
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
return successMap, err
}
msg, err := message.DefaultSVC().GetMessageByID(ctx, messageID)
if err != nil {
return nil, err
}
if msg == nil {
return nil, vo.NewError(errno.ErrMessageNodeOperationFail, errorx.KV("cause", "message not found"))
}
if msg.Content == newContent {
return successMap, nil
}
t, existed, err := workflow.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: appID,
Name: ptr.Of(conversationName),
Version: ptr.Of(version),
})
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if existed {
sts, existed, err := workflow.GetRepository().GetStaticConversationByTemplateID(ctx, env, userID, connectorID, t.TemplateID)
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if !existed {
return failedMap, nil
}
_, err = crossmessage.DefaultSVC().Edit(ctx, &model.Message{ConversationID: sts.ConversationID, ID: messageID, Content: newContent})
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
return successMap, nil
} else {
dyConversation, existed, err := workflow.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if !existed {
return failedMap, nil
}
_, err = crossmessage.DefaultSVC().Edit(ctx, &model.Message{ConversationID: dyConversation.ConversationID, ID: messageID, Content: newContent})
if err != nil {
return nil, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
return successMap, nil
}
}

View File

@@ -0,0 +1,207 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conversation
import (
"context"
"errors"
"fmt"
"strconv"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"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/ternary"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type MessageListConfig struct{}
type MessageList struct{}
func (m *MessageListConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
ns := &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeMessageList,
Name: n.Data.Meta.Title,
Configs: m,
}
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
return nil, err
}
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
return nil, err
}
return ns, nil
}
func (m *MessageListConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
return &MessageList{}, nil
}
func (m *MessageList) getConversationIDByName(ctx context.Context, env vo.Env, appID *int64, version, conversationName string, userID, connectorID int64) (int64, error) {
template, isExist, err := workflow.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: appID,
Name: ptr.Of(conversationName),
Version: ptr.Of(version),
})
if err != nil {
return 0, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
var conversationID int64
if isExist {
sc, _, err := workflow.GetRepository().GetStaticConversationByTemplateID(ctx, env, userID, connectorID, template.TemplateID)
if err != nil {
return 0, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if sc != nil {
conversationID = sc.ConversationID
}
} else {
dc, _, err := workflow.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
if err != nil {
return 0, vo.WrapError(errno.ErrMessageNodeOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error()))
}
if dc != nil {
conversationID = dc.ConversationID
}
}
return conversationID, nil
}
func (m *MessageList) Invoke(ctx context.Context, input map[string]any) (map[string]any, error) {
var (
execCtx = execute.GetExeCtx(ctx)
env = ternary.IFElse(execCtx.ExeCfg.Mode == workflowModel.ExecuteModeRelease, vo.Online, vo.Draft)
appID = execCtx.ExeCfg.AppID
agentID = execCtx.ExeCfg.AgentID
version = execCtx.ExeCfg.Version
connectorID = execCtx.ExeCfg.ConnectorID
userID = execCtx.ExeCfg.Operator
)
conversationName, ok := input["conversationName"].(string)
if !ok {
return nil, vo.WrapError(errno.ErrConversationNodeInvalidOperation, errors.New("ConversationName is required"))
}
var conversationID int64
var err error
var resolvedAppID int64
if appID == nil {
if conversationName != "Default" {
return nil, vo.WrapError(errno.ErrOnlyDefaultConversationAllowInAgentScenario, errors.New("conversation node only allow in application"))
}
if agentID == nil || execCtx.ExeCfg.ConversationID == nil {
return map[string]any{
"messageList": []any{},
"firstId": "0",
"lastId": "0",
"hasMore": false,
}, nil
}
conversationID = *execCtx.ExeCfg.ConversationID
resolvedAppID = *agentID
} else {
conversationID, err = m.getConversationIDByName(ctx, env, appID, version, conversationName, userID, connectorID)
if err != nil {
return nil, err
}
resolvedAppID = *appID
}
req := &crossmessage.MessageListRequest{
UserID: userID,
AppID: resolvedAppID,
ConversationID: conversationID,
}
if req.ConversationID == 0 {
return map[string]any{
"messageList": []any{},
"firstId": "0",
"lastId": "0",
"hasMore": false,
}, nil
}
limit, ok := input["limit"].(int64)
if ok {
if limit > 0 && limit <= 50 {
req.Limit = limit
} else {
req.Limit = 50
}
} else {
req.Limit = 50
}
beforeID, ok := input["beforeId"].(string)
if ok {
req.BeforeID = &beforeID
}
afterID, ok := input["afterId"].(string)
if ok {
req.AfterID = &afterID
}
if beforeID != "" && afterID != "" {
return nil, vo.WrapError(errno.ErrInvalidParameter, fmt.Errorf("BeforeID and AfterID cannot be set at the same time"))
}
ml, err := crossmessage.DefaultSVC().MessageList(ctx, req)
if err != nil {
return nil, err
}
var messageList []any
for _, msg := range ml.Messages {
content, err := nodes.ConvertMessageToString(ctx, msg)
if err != nil {
return nil, err
}
messageList = append(messageList, map[string]any{
"messageId": strconv.FormatInt(msg.ID, 10),
"role": string(msg.Role),
"contentType": msg.ContentType,
"content": content,
})
}
return map[string]any{
"messageList": messageList,
"firstId": ml.FirstID,
"lastId": ml.LastID,
"hasMore": ml.HasMore,
}, nil
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conversation
import (
"context"
"errors"
"fmt"
"strconv"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type UpdateConversationConfig struct{}
type UpdateConversation struct{}
func (c *UpdateConversationConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
ns := &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeConversationUpdate,
Name: n.Data.Meta.Title,
Configs: c,
}
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
return nil, err
}
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
return nil, err
}
return ns, nil
}
func (c *UpdateConversationConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
return &UpdateConversation{}, nil
}
func (c *UpdateConversation) Invoke(ctx context.Context, in map[string]any) (map[string]any, error) {
var (
execCtx = execute.GetExeCtx(ctx)
env = ternary.IFElse(execCtx.ExeCfg.Mode == workflowModel.ExecuteModeRelease, vo.Online, vo.Draft)
appID = execCtx.ExeCfg.AppID
agentID = execCtx.ExeCfg.AgentID
version = execCtx.ExeCfg.Version
connectorID = execCtx.ExeCfg.ConnectorID
userID = execCtx.ExeCfg.Operator
)
cName, ok := in["conversationName"]
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("conversation name is required"))
}
conversationName := cName.(string)
ncName, ok := in["newConversationName"]
if !ok {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("new conversationName name is required"))
}
newConversationName := ncName.(string)
if agentID != nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, fmt.Errorf("in the agent scenario, update conversation is not available"))
}
if appID == nil {
return nil, vo.WrapError(errno.ErrConversationNodesNotAvailable, errors.New("conversation update node, app id is required"))
}
_, existed, err := wf.GetRepository().GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: appID,
Name: ptr.Of(conversationName),
Version: ptr.Of(version),
})
if err != nil {
return nil, err
}
if existed {
return nil, vo.WrapError(errno.ErrConversationNodeInvalidOperation, fmt.Errorf("only conversation created through nodes are allowed to be modified or deleted"))
}
conversation, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, conversationName)
if err != nil {
return nil, err
}
if !existed {
return map[string]any{
"conversationId": "0",
"isSuccess": false,
"isExisted": false,
}, nil
}
ncConversation, existed, err := wf.GetRepository().GetDynamicConversationByName(ctx, env, *appID, connectorID, userID, newConversationName)
if err != nil {
return nil, err
}
if existed {
return map[string]any{
"conversationId": strconv.FormatInt(ncConversation.ConversationID, 10),
"isSuccess": false,
"isExisted": true,
}, nil
}
err = wf.GetRepository().UpdateDynamicConversationNameByID(ctx, env, conversation.ID, newConversationName)
if err != nil {
return nil, err
}
return map[string]any{
"conversationId": strconv.FormatInt(conversation.ConversationID, 10),
"isSuccess": true,
"isExisted": false,
}, nil
}

View File

@@ -20,6 +20,7 @@ import (
"context"
"errors"
"fmt"
"maps"
"strconv"
"strings"
@@ -29,21 +30,26 @@ import (
"github.com/spf13/cast"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/modelmgr"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
crossmodelmgr "github.com/coze-dev/coze-studio/backend/crossdomain/contract/modelmgr"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
schema2 "github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
)
type Config struct {
Intents []string
SystemPrompt string
IsFastMode bool
LLMParams *model.LLMParams
Intents []string
SystemPrompt string
IsFastMode bool
LLMParams *model.LLMParams
ChatHistorySetting *vo.ChatHistorySetting
}
func (c *Config) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema2.NodeSchema, error) {
@@ -59,6 +65,10 @@ func (c *Config) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*
return nil, fmt.Errorf("intent detector node's llmParam is nil")
}
if n.Data.Inputs.ChatHistorySetting != nil {
c.ChatHistorySetting = n.Data.Inputs.ChatHistorySetting
}
llmParam, ok := param.(vo.IntentDetectorLLMParam)
if !ok {
return nil, fmt.Errorf("llm node's llmParam must be LLMParam, got %v", llmParam)
@@ -141,14 +151,16 @@ func (c *Config) Build(ctx context.Context, _ *schema2.NodeSchema, _ ...schema2.
&schema.Message{Content: sptTemplate, Role: schema.System},
&schema.Message{Content: "{{query}}", Role: schema.User})
r, err := chain.AppendChatTemplate(prompts).AppendChatModel(m).Compile(ctx)
r, err := chain.AppendChatTemplate(newHistoryChatTemplate(prompts, c.ChatHistorySetting)).AppendChatModel(m).Compile(ctx)
if err != nil {
return nil, err
}
return &IntentDetector{
isFastMode: c.IsFastMode,
systemPrompt: c.SystemPrompt,
runner: r,
isFastMode: c.IsFastMode,
systemPrompt: c.SystemPrompt,
runner: r,
ChatHistorySetting: c.ChatHistorySetting,
}, nil
}
@@ -182,6 +194,10 @@ func (c *Config) ExpectPorts(ctx context.Context, n *vo.Node) []string {
return expects
}
type contextKey string
const chatHistoryKey contextKey = "chatHistory"
const SystemIntentPrompt = `
# Role
You are an intention classification expert, good at being able to judge which classification the user's input belongs to.
@@ -240,9 +256,10 @@ Note:
const classificationID = "classificationId"
type IntentDetector struct {
isFastMode bool
systemPrompt string
runner compose.Runnable[map[string]any, *schema.Message]
isFastMode bool
systemPrompt string
runner compose.Runnable[map[string]any, *schema.Message]
ChatHistorySetting *vo.ChatHistorySetting
}
func (id *IntentDetector) parseToNodeOut(content string) (map[string]any, error) {
@@ -320,3 +337,66 @@ func toIntentString(its []string) (string, error) {
return sonic.MarshalString(vs)
}
func (id *IntentDetector) ToCallbackInput(ctx context.Context, in map[string]any) (map[string]any, error) {
if id.ChatHistorySetting == nil || !id.ChatHistorySetting.EnableChatHistory {
return in, nil
}
var messages []*crossmessage.WfMessage
var scMessages []*schema.Message
var sectionID *int64
execCtx := execute.GetExeCtx(ctx)
if execCtx != nil {
messages = execCtx.ExeCfg.ConversationHistory
scMessages = execCtx.ExeCfg.ConversationHistorySchemaMessages
sectionID = execCtx.ExeCfg.SectionID
}
ret := map[string]any{
"chatHistory": []any{},
}
maps.Copy(ret, in)
if len(messages) == 0 {
return ret, nil
}
if sectionID != nil && messages[0].SectionID != *sectionID {
return ret, nil
}
maxRounds := int(id.ChatHistorySetting.ChatHistoryRound)
if execCtx != nil && execCtx.ExeCfg.MaxHistoryRounds != nil {
maxRounds = min(int(*execCtx.ExeCfg.MaxHistoryRounds), maxRounds)
}
count := 0
startIdx := 0
for i := len(messages) - 1; i >= 0; i-- {
if messages[i].Role == schema.User {
count++
}
if count >= maxRounds {
startIdx = i
break
}
}
var historyMessages []any
for _, msg := range messages[startIdx:] {
content, err := nodes.ConvertMessageToString(ctx, msg)
if err != nil {
logs.CtxWarnf(ctx, "failed to convert message to string: %v", err)
continue
}
historyMessages = append(historyMessages, map[string]any{
"role": string(msg.Role),
"content": content,
})
}
ctxcache.Store(ctx, chatHistoryKey, scMessages[startIdx:])
ret["chatHistory"] = historyMessages
return ret, nil
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package intentdetector
import (
"context"
"fmt"
"github.com/cloudwego/eino/components/prompt"
"github.com/cloudwego/eino/schema"
"github.com/coze-dev/coze-studio/backend/api/model/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
)
type historyChatTemplate struct {
basePrompt prompt.ChatTemplate
chatHistorySetting *vo.ChatHistorySetting
}
func newHistoryChatTemplate(basePrompt prompt.ChatTemplate, chatHistorySetting *vo.ChatHistorySetting) prompt.ChatTemplate {
return &historyChatTemplate{
basePrompt: basePrompt,
chatHistorySetting: chatHistorySetting,
}
}
func (t *historyChatTemplate) Format(ctx context.Context, vs map[string]any, opts ...prompt.Option) ([]*schema.Message, error) {
baseMessages, err := t.basePrompt.Format(ctx, vs, opts...)
if err != nil {
return nil, fmt.Errorf("failed to format base prompt: %w", err)
}
if len(baseMessages) == 0 {
return nil, fmt.Errorf("base prompt returned no messages")
}
if t.chatHistorySetting == nil || !t.chatHistorySetting.EnableChatHistory {
return baseMessages, nil
}
exeCtx := execute.GetExeCtx(ctx)
if exeCtx == nil {
logs.CtxWarnf(ctx, "execute context is nil, skipping chat history")
return baseMessages, nil
}
if exeCtx.ExeCfg.WorkflowMode != workflow.WorkflowMode_ChatFlow {
return baseMessages, nil
}
historyMessages, ok := ctxcache.Get[[]*schema.Message](ctx, chatHistoryKey)
if !ok || len(historyMessages) == 0 {
logs.CtxWarnf(ctx, "conversation history is empty")
return baseMessages, nil
}
if len(historyMessages) == 0 {
return baseMessages, nil
}
finalMessages := make([]*schema.Message, 0, len(baseMessages)+len(historyMessages))
finalMessages = append(finalMessages, baseMessages[0]) // System prompt
finalMessages = append(finalMessages, historyMessages...)
if len(baseMessages) > 1 {
finalMessages = append(finalMessages, baseMessages[1:]...) // User prompt and any others
}
return finalMessages, nil
}

View File

@@ -19,24 +19,37 @@ package knowledge
import (
"context"
"errors"
"maps"
"github.com/spf13/cast"
einoSchema "github.com/cloudwego/eino/schema"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/knowledge"
"github.com/coze-dev/coze-studio/backend/api/model/workflow"
crossknowledge "github.com/coze-dev/coze-studio/backend/crossdomain/contract/knowledge"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
)
const outputList = "outputList"
type contextKey string
const chatHistoryKey contextKey = "chatHistory"
type RetrieveConfig struct {
KnowledgeIDs []int64
RetrievalStrategy *knowledge.RetrievalStrategy
KnowledgeIDs []int64
RetrievalStrategy *knowledge.RetrievalStrategy
ChatHistorySetting *vo.ChatHistorySetting
}
func (r *RetrieveConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
@@ -60,6 +73,10 @@ func (r *RetrieveConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOp
}
r.KnowledgeIDs = knowledgeIDs
if inputs.ChatHistorySetting != nil {
r.ChatHistorySetting = inputs.ChatHistorySetting
}
retrievalStrategy := &knowledge.RetrievalStrategy{}
var getDesignatedParamContent = func(name string) (any, bool) {
@@ -154,14 +171,16 @@ func (r *RetrieveConfig) Build(_ context.Context, _ *schema.NodeSchema, _ ...sch
}
return &Retrieve{
knowledgeIDs: r.KnowledgeIDs,
retrievalStrategy: r.RetrievalStrategy,
knowledgeIDs: r.KnowledgeIDs,
retrievalStrategy: r.RetrievalStrategy,
ChatHistorySetting: r.ChatHistorySetting,
}, nil
}
type Retrieve struct {
knowledgeIDs []int64
retrievalStrategy *knowledge.RetrievalStrategy
knowledgeIDs []int64
retrievalStrategy *knowledge.RetrievalStrategy
ChatHistorySetting *vo.ChatHistorySetting
}
func (kr *Retrieve) Invoke(ctx context.Context, input map[string]any) (map[string]any, error) {
@@ -173,6 +192,7 @@ func (kr *Retrieve) Invoke(ctx context.Context, input map[string]any) (map[strin
req := &knowledge.RetrieveRequest{
Query: query,
KnowledgeIDs: kr.knowledgeIDs,
ChatHistory: kr.GetChatHistoryOrNil(ctx, kr.ChatHistorySetting),
Strategy: kr.retrievalStrategy,
}
@@ -190,3 +210,89 @@ func (kr *Retrieve) Invoke(ctx context.Context, input map[string]any) (map[strin
return result, nil
}
func (kr *Retrieve) GetChatHistoryOrNil(ctx context.Context, ChatHistorySetting *vo.ChatHistorySetting) []*einoSchema.Message {
if ChatHistorySetting == nil || !ChatHistorySetting.EnableChatHistory {
return nil
}
exeCtx := execute.GetExeCtx(ctx)
if exeCtx == nil {
logs.CtxWarnf(ctx, "execute context is nil, skipping chat history")
return nil
}
if exeCtx.ExeCfg.WorkflowMode != workflow.WorkflowMode_ChatFlow {
return nil
}
historyMessages, ok := ctxcache.Get[[]*einoSchema.Message](ctx, chatHistoryKey)
if !ok || len(historyMessages) == 0 {
logs.CtxWarnf(ctx, "conversation history is empty")
return nil
}
return historyMessages
}
func (kr *Retrieve) ToCallbackInput(ctx context.Context, in map[string]any) (map[string]any, error) {
if kr.ChatHistorySetting == nil || !kr.ChatHistorySetting.EnableChatHistory {
return in, nil
}
var messages []*crossmessage.WfMessage
var scMessages []*einoSchema.Message
var sectionID *int64
execCtx := execute.GetExeCtx(ctx)
if execCtx != nil {
messages = execCtx.ExeCfg.ConversationHistory
scMessages = execCtx.ExeCfg.ConversationHistorySchemaMessages
sectionID = execCtx.ExeCfg.SectionID
}
ret := map[string]any{
"chatHistory": []any{},
}
maps.Copy(ret, in)
if len(messages) == 0 {
return ret, nil
}
if sectionID != nil && messages[0].SectionID != *sectionID {
return ret, nil
}
maxRounds := int(kr.ChatHistorySetting.ChatHistoryRound)
if execCtx != nil && execCtx.ExeCfg.MaxHistoryRounds != nil {
maxRounds = min(int(*execCtx.ExeCfg.MaxHistoryRounds), maxRounds)
}
count := 0
startIdx := 0
for i := len(messages) - 1; i >= 0; i-- {
if messages[i].Role == einoSchema.User {
count++
}
if count >= maxRounds {
startIdx = i
break
}
}
var historyMessages []any
for _, msg := range messages[startIdx:] {
content, err := nodes.ConvertMessageToString(ctx, msg)
if err != nil {
logs.CtxWarnf(ctx, "failed to convert message to string: %v", err)
continue
}
historyMessages = append(historyMessages, map[string]any{
"role": string(msg.Role),
"content": content,
})
}
ctxcache.Store(ctx, chatHistoryKey, scMessages[startIdx:])
ret["chatHistory"] = historyMessages
return ret, nil
}

View File

@@ -40,6 +40,7 @@ import (
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
workflow3 "github.com/coze-dev/coze-studio/backend/api/model/workflow"
crossknowledge "github.com/coze-dev/coze-studio/backend/crossdomain/contract/knowledge"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
crossmodelmgr "github.com/coze-dev/coze-studio/backend/crossdomain/contract/modelmgr"
crossplugin "github.com/coze-dev/coze-studio/backend/crossdomain/contract/plugin"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
@@ -59,6 +60,10 @@ import (
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type contextKey string
const chatHistoryKey contextKey = "chatHistory"
type Format int
const (
@@ -167,12 +172,14 @@ type KnowledgeRecallConfig struct {
}
type Config struct {
SystemPrompt string
UserPrompt string
OutputFormat Format
LLMParams *crossmodel.LLMParams
FCParam *vo.FCParam
BackupLLMParams *crossmodel.LLMParams
SystemPrompt string
UserPrompt string
OutputFormat Format
LLMParams *crossmodel.LLMParams
FCParam *vo.FCParam
BackupLLMParams *crossmodel.LLMParams
ChatHistorySetting *vo.ChatHistorySetting
AssociateStartNodeUserInputFields map[string]struct{}
}
func (c *Config) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema2.NodeSchema, error) {
@@ -202,6 +209,13 @@ func (c *Config) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*
c.SystemPrompt = convertedLLMParam.SystemPrompt
c.UserPrompt = convertedLLMParam.Prompt
if convertedLLMParam.EnableChatHistory {
c.ChatHistorySetting = &vo.ChatHistorySetting{
EnableChatHistory: true,
ChatHistoryRound: convertedLLMParam.ChatHistoryRound,
}
}
var resFormat Format
switch convertedLLMParam.ResponseFormat {
case crossmodel.ResponseFormatText:
@@ -273,6 +287,15 @@ func (c *Config) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*
}
}
c.AssociateStartNodeUserInputFields = make(map[string]struct{})
for _, info := range ns.InputSources {
if len(info.Path) == 1 && info.Source.Ref != nil && info.Source.Ref.FromNodeKey == entity.EntryNodeKey {
if compose.FromFieldPath(info.Source.Ref.FromPath).Equals(compose.FromField("USER_INPUT")) {
c.AssociateStartNodeUserInputFields[info.Path[0]] = struct{}{}
}
}
}
return ns, nil
}
@@ -320,7 +343,14 @@ func llmParamsToLLMParam(params vo.LLMParam) (*crossmodel.LLMParams, error) {
case "systemPrompt":
strVal := param.Input.Value.Content.(string)
p.SystemPrompt = strVal
case "chatHistoryRound", "generationDiversity", "frequencyPenalty", "presencePenalty":
case "chatHistoryRound":
strVal := param.Input.Value.Content.(string)
int64Val, err := strconv.ParseInt(strVal, 10, 64)
if err != nil {
return nil, err
}
p.ChatHistoryRound = int64Val
case "generationDiversity", "frequencyPenalty", "presencePenalty":
// do nothing
case "topP":
strVal := param.Input.Value.Content.(string)
@@ -590,11 +620,12 @@ func (c *Config) Build(ctx context.Context, ns *schema2.NodeSchema, _ ...schema2
inputs[knowledgeUserPromptTemplateKey] = &vo.TypeInfo{
Type: vo.DataTypeString,
}
sp := newPromptTpl(schema.System, c.SystemPrompt, inputs, nil)
up := newPromptTpl(schema.User, userPrompt, inputs, []string{knowledgeUserPromptTemplateKey})
sp := newPromptTpl(schema.System, c.SystemPrompt, inputs)
up := newPromptTpl(schema.User, userPrompt, inputs, withReservedKeys([]string{knowledgeUserPromptTemplateKey}), withAssociateUserInputFields(c.AssociateStartNodeUserInputFields))
template := newPrompts(sp, up, modelWithInfo)
templateWithChatHistory := newPromptsWithChatHistory(template, c.ChatHistorySetting)
_ = g.AddChatTemplateNode(templateNodeKey, template,
_ = g.AddChatTemplateNode(templateNodeKey, templateWithChatHistory,
compose.WithStatePreHandler(func(ctx context.Context, in map[string]any, state llmState) (map[string]any, error) {
for k, v := range state {
in[k] = v
@@ -604,10 +635,12 @@ func (c *Config) Build(ctx context.Context, ns *schema2.NodeSchema, _ ...schema2
_ = g.AddEdge(knowledgeLambdaKey, templateNodeKey)
} else {
sp := newPromptTpl(schema.System, c.SystemPrompt, ns.InputTypes, nil)
up := newPromptTpl(schema.User, userPrompt, ns.InputTypes, nil)
sp := newPromptTpl(schema.System, c.SystemPrompt, ns.InputTypes)
up := newPromptTpl(schema.User, userPrompt, ns.InputTypes, withAssociateUserInputFields(c.AssociateStartNodeUserInputFields))
template := newPrompts(sp, up, modelWithInfo)
_ = g.AddChatTemplateNode(templateNodeKey, template)
templateWithChatHistory := newPromptsWithChatHistory(template, c.ChatHistorySetting)
_ = g.AddChatTemplateNode(templateNodeKey, templateWithChatHistory)
_ = g.AddEdge(compose.START, templateNodeKey)
}
@@ -747,10 +780,11 @@ func (c *Config) Build(ctx context.Context, ns *schema2.NodeSchema, _ ...schema2
}
llm := &LLM{
r: r,
outputFormat: format,
requireCheckpoint: requireCheckpoint,
fullSources: ns.FullSources,
r: r,
outputFormat: format,
requireCheckpoint: requireCheckpoint,
fullSources: ns.FullSources,
chatHistorySetting: c.ChatHistorySetting,
}
return llm, nil
@@ -825,10 +859,11 @@ func toRetrievalSearchType(s int64) (knowledge.SearchType, error) {
}
type LLM struct {
r compose.Runnable[map[string]any, map[string]any]
outputFormat Format
requireCheckpoint bool
fullSources map[string]*schema2.SourceInfo
r compose.Runnable[map[string]any, map[string]any]
outputFormat Format
requireCheckpoint bool
fullSources map[string]*schema2.SourceInfo
chatHistorySetting *vo.ChatHistorySetting
}
const (
@@ -1193,6 +1228,68 @@ type ToolInterruptEventStore interface {
ResumeToolInterruptEvent(llmNodeKey vo.NodeKey, toolCallID string) (string, error)
}
func (l *LLM) ToCallbackInput(ctx context.Context, input map[string]any) (map[string]any, error) {
if l.chatHistorySetting == nil || !l.chatHistorySetting.EnableChatHistory {
return input, nil
}
var messages []*crossmessage.WfMessage
var scMessages []*schema.Message
var sectionID *int64
execCtx := execute.GetExeCtx(ctx)
if execCtx != nil {
messages = execCtx.ExeCfg.ConversationHistory
scMessages = execCtx.ExeCfg.ConversationHistorySchemaMessages
sectionID = execCtx.ExeCfg.SectionID
}
ret := map[string]any{
"chatHistory": []any{},
}
maps.Copy(ret, input)
if len(messages) == 0 {
return ret, nil
}
if sectionID != nil && messages[0].SectionID != *sectionID {
return ret, nil
}
maxRounds := int(l.chatHistorySetting.ChatHistoryRound)
if execCtx != nil && execCtx.ExeCfg.MaxHistoryRounds != nil {
maxRounds = min(int(*execCtx.ExeCfg.MaxHistoryRounds), maxRounds)
}
count := 0
startIdx := 0
for i := len(messages) - 1; i >= 0; i-- {
if messages[i].Role == schema.User {
count++
}
if count >= maxRounds {
startIdx = i
break
}
}
var historyMessages []any
for _, msg := range messages[startIdx:] {
content, err := nodes.ConvertMessageToString(ctx, msg)
if err != nil {
logs.CtxWarnf(ctx, "failed to convert message to string: %v", err)
continue
}
historyMessages = append(historyMessages, map[string]any{
"role": string(msg.Role),
"content": content,
})
}
ctxcache.Store(ctx, chatHistoryKey, scMessages[startIdx:])
ret["chatHistory"] = historyMessages
return ret, nil
}
func (l *LLM) ToCallbackOutput(ctx context.Context, output map[string]any) (*nodes.StructuredCallbackOutput, error) {
c := execute.GetExeCtx(ctx)
if c == nil {

View File

@@ -23,12 +23,14 @@ import (
"github.com/cloudwego/eino/components/prompt"
"github.com/cloudwego/eino/schema"
"github.com/coze-dev/coze-studio/backend/api/model/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
schema2 "github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
"github.com/coze-dev/coze-studio/backend/infra/contract/modelmgr"
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
)
@@ -38,12 +40,30 @@ type prompts struct {
mwi ModelWithInfo
}
type promptsWithChatHistory struct {
prompts *prompts
cfg *vo.ChatHistorySetting
}
func withReservedKeys(keys []string) func(tpl *promptTpl) {
return func(tpl *promptTpl) {
tpl.reservedKeys = keys
}
}
func withAssociateUserInputFields(fs map[string]struct{}) func(tpl *promptTpl) {
return func(tpl *promptTpl) {
tpl.associateUserInputFields = fs
}
}
type promptTpl struct {
role schema.RoleType
tpl string
parts []promptPart
hasMultiModal bool
reservedKeys []string
role schema.RoleType
tpl string
parts []promptPart
hasMultiModal bool
reservedKeys []string
associateUserInputFields map[string]struct{}
}
type promptPart struct {
@@ -54,12 +74,20 @@ type promptPart struct {
func newPromptTpl(role schema.RoleType,
tpl string,
inputTypes map[string]*vo.TypeInfo,
reservedKeys []string,
opts ...func(*promptTpl),
) *promptTpl {
if len(tpl) == 0 {
return nil
}
pTpl := &promptTpl{
role: role,
tpl: tpl,
}
for _, opt := range opts {
opt(pTpl)
}
parts := nodes.ParseTemplate(tpl)
promptParts := make([]promptPart, 0, len(parts))
hasMultiModal := false
@@ -87,14 +115,10 @@ func newPromptTpl(role schema.RoleType,
hasMultiModal = true
}
pTpl.parts = promptParts
pTpl.hasMultiModal = hasMultiModal
return &promptTpl{
role: role,
tpl: tpl,
parts: promptParts,
hasMultiModal: hasMultiModal,
reservedKeys: reservedKeys,
}
return pTpl
}
const sourceKey = "sources_%s"
@@ -107,23 +131,53 @@ func newPrompts(sp, up *promptTpl, model ModelWithInfo) *prompts {
}
}
func newPromptsWithChatHistory(prompts *prompts, cfg *vo.ChatHistorySetting) *promptsWithChatHistory {
return &promptsWithChatHistory{
prompts: prompts,
cfg: cfg,
}
}
func (pl *promptTpl) render(ctx context.Context, vs map[string]any,
sources map[string]*schema2.SourceInfo,
supportedModals map[modelmgr.Modal]bool,
) (*schema.Message, error) {
if !pl.hasMultiModal || len(supportedModals) == 0 {
var opts []nodes.RenderOption
if len(pl.reservedKeys) > 0 {
opts = append(opts, nodes.WithReservedKey(pl.reservedKeys...))
isChatFlow := execute.GetExeCtx(ctx).ExeCfg.WorkflowMode == workflow.WorkflowMode_ChatFlow
userMessage := execute.GetExeCtx(ctx).ExeCfg.UserMessage
if !isChatFlow {
if !pl.hasMultiModal || len(supportedModals) == 0 {
var opts []nodes.RenderOption
if len(pl.reservedKeys) > 0 {
opts = append(opts, nodes.WithReservedKey(pl.reservedKeys...))
}
r, err := nodes.Render(ctx, pl.tpl, vs, sources, opts...)
if err != nil {
return nil, err
}
return &schema.Message{
Role: pl.role,
Content: r,
}, nil
}
r, err := nodes.Render(ctx, pl.tpl, vs, sources, opts...)
if err != nil {
return nil, err
} else {
if (!pl.hasMultiModal || len(supportedModals) == 0) &&
(len(pl.associateUserInputFields) == 0 ||
(len(pl.associateUserInputFields) > 0 && userMessage != nil && userMessage.MultiContent == nil)) {
var opts []nodes.RenderOption
if len(pl.reservedKeys) > 0 {
opts = append(opts, nodes.WithReservedKey(pl.reservedKeys...))
}
r, err := nodes.Render(ctx, pl.tpl, vs, sources, opts...)
if err != nil {
return nil, err
}
return &schema.Message{
Role: pl.role,
Content: r,
}, nil
}
return &schema.Message{
Role: pl.role,
Content: r,
}, nil
}
multiParts := make([]schema.ChatMessagePart, 0, len(pl.parts))
@@ -141,6 +195,13 @@ func (pl *promptTpl) render(ctx context.Context, vs map[string]any,
continue
}
if _, ok := pl.associateUserInputFields[part.part.Value]; ok && userMessage != nil && isChatFlow {
for _, p := range userMessage.MultiContent {
multiParts = append(multiParts, transformMessagePart(p, supportedModals))
}
continue
}
skipped, invalid := part.part.Skipped(sources)
if invalid {
var reserved bool
@@ -164,6 +225,7 @@ func (pl *promptTpl) render(ctx context.Context, vs map[string]any,
if err != nil {
return nil, err
}
if part.fileType == nil {
multiParts = append(multiParts, schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeText,
@@ -172,64 +234,38 @@ func (pl *promptTpl) render(ctx context.Context, vs map[string]any,
continue
}
var originalPart schema.ChatMessagePart
switch *part.fileType {
case vo.FileTypeImage, vo.FileTypeSVG:
if _, ok := supportedModals[modelmgr.ModalImage]; !ok {
multiParts = append(multiParts, schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeText,
Text: r,
})
} else {
multiParts = append(multiParts, schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeImageURL,
ImageURL: &schema.ChatMessageImageURL{
URL: r,
},
})
originalPart = schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeImageURL,
ImageURL: &schema.ChatMessageImageURL{
URL: r,
},
}
case vo.FileTypeAudio, vo.FileTypeVoice:
if _, ok := supportedModals[modelmgr.ModalAudio]; !ok {
multiParts = append(multiParts, schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeText,
Text: r,
})
} else {
multiParts = append(multiParts, schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeAudioURL,
AudioURL: &schema.ChatMessageAudioURL{
URL: r,
},
})
originalPart = schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeAudioURL,
AudioURL: &schema.ChatMessageAudioURL{
URL: r,
},
}
case vo.FileTypeVideo:
if _, ok := supportedModals[modelmgr.ModalVideo]; !ok {
multiParts = append(multiParts, schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeText,
Text: r,
})
} else {
multiParts = append(multiParts, schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeVideoURL,
VideoURL: &schema.ChatMessageVideoURL{
URL: r,
},
})
originalPart = schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeVideoURL,
VideoURL: &schema.ChatMessageVideoURL{
URL: r,
},
}
default:
if _, ok := supportedModals[modelmgr.ModalFile]; !ok {
multiParts = append(multiParts, schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeText,
Text: r,
})
} else {
multiParts = append(multiParts, schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeFileURL,
FileURL: &schema.ChatMessageFileURL{
URL: r,
},
})
originalPart = schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeFileURL,
FileURL: &schema.ChatMessageFileURL{
URL: r,
},
}
}
multiParts = append(multiParts, transformMessagePart(originalPart, supportedModals))
}
return &schema.Message{
@@ -238,6 +274,40 @@ func (pl *promptTpl) render(ctx context.Context, vs map[string]any,
}, nil
}
func transformMessagePart(part schema.ChatMessagePart, supportedModals map[modelmgr.Modal]bool) schema.ChatMessagePart {
switch part.Type {
case schema.ChatMessagePartTypeImageURL:
if _, ok := supportedModals[modelmgr.ModalImage]; !ok {
return schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeText,
Text: part.ImageURL.URL,
}
}
case schema.ChatMessagePartTypeAudioURL:
if _, ok := supportedModals[modelmgr.ModalAudio]; !ok {
return schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeText,
Text: part.AudioURL.URL,
}
}
case schema.ChatMessagePartTypeVideoURL:
if _, ok := supportedModals[modelmgr.ModalVideo]; !ok {
return schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeText,
Text: part.VideoURL.URL,
}
}
case schema.ChatMessagePartTypeFileURL:
if _, ok := supportedModals[modelmgr.ModalFile]; !ok {
return schema.ChatMessagePart{
Type: schema.ChatMessagePartTypeText,
Text: part.FileURL.URL,
}
}
}
return part
}
func (p *prompts) Format(ctx context.Context, vs map[string]any, _ ...prompt.Option) (
_ []*schema.Message, err error,
) {
@@ -288,3 +358,45 @@ func (p *prompts) Format(ctx context.Context, vs map[string]any, _ ...prompt.Opt
return []*schema.Message{systemMsg, userMsg}, nil
}
func (p *promptsWithChatHistory) Format(ctx context.Context, vs map[string]any, _ ...prompt.Option) (
[]*schema.Message, error) {
baseMessages, err := p.prompts.Format(ctx, vs)
if err != nil {
return nil, err
}
if p.cfg == nil || !p.cfg.EnableChatHistory {
return baseMessages, nil
}
exeCtx := execute.GetExeCtx(ctx)
if exeCtx == nil {
logs.CtxWarnf(ctx, "execute context is nil, skipping chat history")
return baseMessages, nil
}
if exeCtx.ExeCfg.WorkflowMode != workflow.WorkflowMode_ChatFlow {
return baseMessages, nil
}
historyMessages, ok := ctxcache.Get[[]*schema.Message](ctx, chatHistoryKey)
if !ok || len(historyMessages) == 0 {
logs.CtxWarnf(ctx, "conversation history is empty")
return baseMessages, nil
}
if len(historyMessages) == 0 {
return baseMessages, nil
}
finalMessages := make([]*schema.Message, 0, len(baseMessages)+len(historyMessages))
if len(baseMessages) > 0 && baseMessages[0].Role == schema.System {
finalMessages = append(finalMessages, baseMessages[0])
baseMessages = baseMessages[1:]
}
finalMessages = append(finalMessages, historyMessages...)
finalMessages = append(finalMessages, baseMessages...)
return finalMessages, nil
}

View File

@@ -17,14 +17,17 @@
package nodes
import (
"context"
"errors"
"fmt"
"maps"
"reflect"
"strings"
"github.com/cloudwego/eino/compose"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
"github.com/coze-dev/coze-studio/backend/types/errno"
@@ -279,3 +282,30 @@ func GetConcatFunc(typ reflect.Type) func(reflect.Value) (reflect.Value, error)
return nil
}
func ConvertMessageToString(_ context.Context, msg *crossmessage.WfMessage) (string, error) {
if msg.MultiContent != nil {
var textContents []string
var otherContents []string
for _, m := range msg.MultiContent {
if m.Text != nil {
textContents = append(textContents, ptr.From(m.Text))
} else if m.Uri != nil {
otherContents = append(otherContents, ptr.From(m.Url))
}
}
var allParts []string
if len(textContents) > 0 {
allParts = append(allParts, textContents...)
}
if len(otherContents) > 0 {
allParts = append(allParts, otherContents...)
}
return strings.Join(allParts, ","), nil
} else if msg.Text != nil {
return ptr.From(msg.Text), nil
} else {
return "", vo.WrapError(errno.ErrInvalidParameter, errors.New("message is invalid"))
}
}

View File

@@ -0,0 +1,940 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package repo
import (
"context"
"errors"
"fmt"
"gorm.io/gen"
"gorm.io/gorm"
crossconversation "github.com/coze-dev/coze-studio/backend/crossdomain/contract/conversation"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo/dal/model"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
const batchSize = 10
func (r *RepositoryImpl) CreateDraftConversationTemplate(ctx context.Context, template *vo.CreateConversationTemplateMeta) (int64, error) {
id, err := r.GenID(ctx)
if err != nil {
return 0, vo.WrapError(errno.ErrIDGenError, err)
}
m := &model.AppConversationTemplateDraft{
ID: id,
AppID: template.AppID,
SpaceID: template.SpaceID,
Name: template.Name,
CreatorID: template.UserID,
TemplateID: id,
}
err = r.query.AppConversationTemplateDraft.WithContext(ctx).Create(m)
if err != nil {
return 0, vo.WrapError(errno.ErrDatabaseError, err)
}
return id, nil
}
func (r *RepositoryImpl) GetConversationTemplate(ctx context.Context, env vo.Env, policy vo.GetConversationTemplatePolicy) (*entity.ConversationTemplate, bool, error) {
var (
appID = policy.AppID
name = policy.Name
version = policy.Version
templateID = policy.TemplateID
)
conditions := make([]gen.Condition, 0)
if env == vo.Draft {
if appID != nil {
conditions = append(conditions, r.query.AppConversationTemplateDraft.AppID.Eq(*appID))
}
if name != nil {
conditions = append(conditions, r.query.AppConversationTemplateDraft.Name.Eq(*name))
}
if templateID != nil {
conditions = append(conditions, r.query.AppConversationTemplateDraft.TemplateID.Eq(*templateID))
}
template, err := r.query.AppConversationTemplateDraft.WithContext(ctx).Where(conditions...).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, vo.WrapError(errno.ErrDatabaseError, err)
}
return &entity.ConversationTemplate{
AppID: template.AppID,
Name: template.Name,
TemplateID: template.TemplateID,
}, true, nil
} else if env == vo.Online {
if policy.Version != nil {
conditions = append(conditions, r.query.AppConversationTemplateOnline.Version.Eq(*version))
}
if appID != nil {
conditions = append(conditions, r.query.AppConversationTemplateOnline.AppID.Eq(*appID))
}
if name != nil {
conditions = append(conditions, r.query.AppConversationTemplateOnline.Name.Eq(*name))
}
if templateID != nil {
conditions = append(conditions, r.query.AppConversationTemplateOnline.TemplateID.Eq(*templateID))
}
template, err := r.query.AppConversationTemplateOnline.WithContext(ctx).Where(conditions...).Order(r.query.AppConversationTemplateOnline.CreatedAt.Desc()).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
return &entity.ConversationTemplate{
AppID: template.AppID,
Name: template.Name,
TemplateID: template.TemplateID,
}, true, nil
}
return nil, false, fmt.Errorf("unknown env %v", env)
}
func (r *RepositoryImpl) UpdateDraftConversationTemplateName(ctx context.Context, templateID int64, name string) error {
_, err := r.query.AppConversationTemplateDraft.WithContext(ctx).Where(
r.query.AppConversationTemplateDraft.TemplateID.Eq(templateID),
).UpdateColumnSimple(r.query.AppConversationTemplateDraft.Name.Value(name))
if err != nil {
return vo.WrapError(errno.ErrDatabaseError, err)
}
return nil
}
func (r *RepositoryImpl) DeleteDraftConversationTemplate(ctx context.Context, templateID int64) (int64, error) {
resultInfo, err := r.query.AppConversationTemplateDraft.WithContext(ctx).Where(
r.query.AppConversationTemplateDraft.TemplateID.Eq(templateID),
).Delete()
if err != nil {
return 0, vo.WrapError(errno.ErrDatabaseError, err)
}
return resultInfo.RowsAffected, nil
}
func (r *RepositoryImpl) DeleteDynamicConversation(ctx context.Context, env vo.Env, id int64) (int64, error) {
if env == vo.Draft {
info, err := r.query.AppDynamicConversationDraft.WithContext(ctx).Where(r.query.AppDynamicConversationDraft.ID.Eq(id)).Delete()
if err != nil {
return 0, vo.WrapError(errno.ErrDatabaseError, err)
}
return info.RowsAffected, nil
} else if env == vo.Online {
info, err := r.query.AppDynamicConversationOnline.WithContext(ctx).Where(r.query.AppDynamicConversationOnline.ID.Eq(id)).Delete()
if err != nil {
return 0, vo.WrapError(errno.ErrDatabaseError, err)
}
return info.RowsAffected, nil
} else {
return 0, fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) ListConversationTemplate(ctx context.Context, env vo.Env, policy *vo.ListConversationTemplatePolicy) ([]*entity.ConversationTemplate, error) {
if env == vo.Draft {
return r.listDraftConversationTemplate(ctx, policy)
} else if env == vo.Online {
return r.listOnlineConversationTemplate(ctx, policy)
} else {
return nil, fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) listDraftConversationTemplate(ctx context.Context, policy *vo.ListConversationTemplatePolicy) ([]*entity.ConversationTemplate, error) {
conditions := make([]gen.Condition, 0)
conditions = append(conditions, r.query.AppConversationTemplateDraft.AppID.Eq(policy.AppID))
if policy.NameLike != nil {
conditions = append(conditions, r.query.AppConversationTemplateDraft.Name.Like("%%"+*policy.NameLike+"%%"))
}
appConversationTemplateDraftDao := r.query.AppConversationTemplateDraft.WithContext(ctx)
var (
templates []*model.AppConversationTemplateDraft
err error
)
if policy.Page != nil {
templates, err = appConversationTemplateDraftDao.Where(conditions...).Offset(policy.Page.Offset()).Limit(policy.Page.Limit()).Find()
} else {
templates, err = appConversationTemplateDraftDao.Where(conditions...).Find()
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return []*entity.ConversationTemplate{}, nil
}
return nil, vo.WrapError(errno.ErrDatabaseError, err)
}
return slices.Transform(templates, func(a *model.AppConversationTemplateDraft) *entity.ConversationTemplate {
return &entity.ConversationTemplate{
SpaceID: a.SpaceID,
AppID: a.AppID,
Name: a.Name,
TemplateID: a.TemplateID,
}
}), nil
}
func (r *RepositoryImpl) listOnlineConversationTemplate(ctx context.Context, policy *vo.ListConversationTemplatePolicy) ([]*entity.ConversationTemplate, error) {
conditions := make([]gen.Condition, 0)
conditions = append(conditions, r.query.AppConversationTemplateOnline.AppID.Eq(policy.AppID))
if policy.Version == nil {
return nil, fmt.Errorf("list online template fail, version is required")
}
conditions = append(conditions, r.query.AppConversationTemplateOnline.Version.Eq(*policy.Version))
if policy.NameLike != nil {
conditions = append(conditions, r.query.AppConversationTemplateOnline.Name.Like("%%"+*policy.NameLike+"%%"))
}
appConversationTemplateOnlineDao := r.query.AppConversationTemplateOnline.WithContext(ctx)
var (
templates []*model.AppConversationTemplateOnline
err error
)
if policy.Page != nil {
templates, err = appConversationTemplateOnlineDao.Where(conditions...).Offset(policy.Page.Offset()).Limit(policy.Page.Limit()).Find()
} else {
templates, err = appConversationTemplateOnlineDao.Where(conditions...).Find()
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return []*entity.ConversationTemplate{}, nil
}
return nil, vo.WrapError(errno.ErrDatabaseError, err)
}
return slices.Transform(templates, func(a *model.AppConversationTemplateOnline) *entity.ConversationTemplate {
return &entity.ConversationTemplate{
SpaceID: a.SpaceID,
AppID: a.AppID,
Name: a.Name,
TemplateID: a.TemplateID,
}
}), nil
}
func (r *RepositoryImpl) MGetStaticConversation(ctx context.Context, env vo.Env, userID, connectorID int64, templateIDs []int64) ([]*entity.StaticConversation, error) {
if env == vo.Draft {
return r.mGetDraftStaticConversation(ctx, userID, connectorID, templateIDs)
} else if env == vo.Online {
return r.mGetOnlineStaticConversation(ctx, userID, connectorID, templateIDs)
} else {
return nil, fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) mGetDraftStaticConversation(ctx context.Context, userID, connectorID int64, templateIDs []int64) ([]*entity.StaticConversation, error) {
conditions := make([]gen.Condition, 0, 3)
conditions = append(conditions, r.query.AppStaticConversationDraft.UserID.Eq(userID))
conditions = append(conditions, r.query.AppStaticConversationDraft.ConnectorID.Eq(connectorID))
if len(templateIDs) == 1 {
conditions = append(conditions, r.query.AppStaticConversationDraft.TemplateID.Eq(templateIDs[0]))
} else {
conditions = append(conditions, r.query.AppStaticConversationDraft.TemplateID.In(templateIDs...))
}
cs, err := r.query.AppStaticConversationDraft.WithContext(ctx).Where(conditions...).Find()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return []*entity.StaticConversation{}, nil
}
return nil, vo.WrapError(errno.ErrDatabaseError, err)
}
return slices.Transform(cs, func(a *model.AppStaticConversationDraft) *entity.StaticConversation {
return &entity.StaticConversation{
TemplateID: a.TemplateID,
ConversationID: a.ConversationID,
UserID: a.UserID,
ConnectorID: a.ConnectorID,
}
}), nil
}
func (r *RepositoryImpl) mGetOnlineStaticConversation(ctx context.Context, userID, connectorID int64, templateIDs []int64) ([]*entity.StaticConversation, error) {
conditions := make([]gen.Condition, 0, 3)
conditions = append(conditions, r.query.AppStaticConversationOnline.UserID.Eq(userID))
conditions = append(conditions, r.query.AppStaticConversationOnline.ConnectorID.Eq(connectorID))
if len(templateIDs) == 1 {
conditions = append(conditions, r.query.AppStaticConversationOnline.TemplateID.Eq(templateIDs[0]))
} else {
conditions = append(conditions, r.query.AppStaticConversationOnline.TemplateID.In(templateIDs...))
}
cs, err := r.query.AppStaticConversationOnline.WithContext(ctx).Where(conditions...).Find()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return []*entity.StaticConversation{}, nil
}
return nil, vo.WrapError(errno.ErrDatabaseError, err)
}
return slices.Transform(cs, func(a *model.AppStaticConversationOnline) *entity.StaticConversation {
return &entity.StaticConversation{
TemplateID: a.TemplateID,
ConversationID: a.ConversationID,
}
}), nil
}
func (r *RepositoryImpl) ListDynamicConversation(ctx context.Context, env vo.Env, policy *vo.ListConversationPolicy) ([]*entity.DynamicConversation, error) {
if env == vo.Draft {
return r.listDraftDynamicConversation(ctx, policy)
} else if env == vo.Online {
return r.listOnlineDynamicConversation(ctx, policy)
} else {
return nil, fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) listDraftDynamicConversation(ctx context.Context, policy *vo.ListConversationPolicy) ([]*entity.DynamicConversation, error) {
var (
appID = policy.APPID
userID = policy.UserID
connectorID = policy.ConnectorID
)
conditions := make([]gen.Condition, 0)
conditions = append(conditions, r.query.AppDynamicConversationDraft.AppID.Eq(appID))
conditions = append(conditions, r.query.AppDynamicConversationDraft.UserID.Eq(userID))
conditions = append(conditions, r.query.AppDynamicConversationDraft.ConnectorID.Eq(connectorID))
if policy.NameLike != nil {
conditions = append(conditions, r.query.AppDynamicConversationDraft.Name.Like("%%"+*policy.NameLike+"%%"))
}
appDynamicConversationDraftDao := r.query.AppDynamicConversationDraft.WithContext(ctx).Where(conditions...)
var (
dynamicConversations = make([]*model.AppDynamicConversationDraft, 0)
err error
)
if policy.Page != nil {
dynamicConversations, err = appDynamicConversationDraftDao.Offset(policy.Page.Offset()).Limit(policy.Page.Limit()).Find()
} else {
dynamicConversations, err = appDynamicConversationDraftDao.Where(conditions...).Find()
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return []*entity.DynamicConversation{}, nil
}
return nil, vo.WrapError(errno.ErrDatabaseError, err)
}
return slices.Transform(dynamicConversations, func(a *model.AppDynamicConversationDraft) *entity.DynamicConversation {
return &entity.DynamicConversation{
ID: a.ID,
Name: a.Name,
UserID: a.UserID,
ConnectorID: a.ConnectorID,
ConversationID: a.ConversationID,
}
}), nil
}
func (r *RepositoryImpl) listOnlineDynamicConversation(ctx context.Context, policy *vo.ListConversationPolicy) ([]*entity.DynamicConversation, error) {
var (
appID = policy.APPID
userID = policy.UserID
connectorID = policy.ConnectorID
)
conditions := make([]gen.Condition, 0)
conditions = append(conditions, r.query.AppDynamicConversationOnline.AppID.Eq(appID))
conditions = append(conditions, r.query.AppDynamicConversationOnline.UserID.Eq(userID))
conditions = append(conditions, r.query.AppDynamicConversationOnline.AppID.Eq(appID))
conditions = append(conditions, r.query.AppDynamicConversationOnline.ConnectorID.Eq(connectorID))
if policy.NameLike != nil {
conditions = append(conditions, r.query.AppDynamicConversationOnline.Name.Like("%%"+*policy.NameLike+"%%"))
}
appDynamicConversationOnlineDao := r.query.AppDynamicConversationOnline.WithContext(ctx).Where(conditions...)
var (
dynamicConversations = make([]*model.AppDynamicConversationOnline, 0)
err error
)
if policy.Page != nil {
dynamicConversations, err = appDynamicConversationOnlineDao.Offset(policy.Page.Offset()).Limit(policy.Page.Limit()).Find()
} else {
dynamicConversations, err = appDynamicConversationOnlineDao.Where(conditions...).Find()
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return []*entity.DynamicConversation{}, nil
}
return nil, vo.WrapError(errno.ErrDatabaseError, err)
}
return slices.Transform(dynamicConversations, func(a *model.AppDynamicConversationOnline) *entity.DynamicConversation {
return &entity.DynamicConversation{
ID: a.ID,
Name: a.Name,
UserID: a.UserID,
ConnectorID: a.ConnectorID,
ConversationID: a.ConversationID,
}
}), nil
}
func (r *RepositoryImpl) GetOrCreateStaticConversation(ctx context.Context, env vo.Env, idGen workflow.ConversationIDGenerator, meta *vo.CreateStaticConversation) (int64, int64, bool, error) {
if env == vo.Draft {
return r.getOrCreateDraftStaticConversation(ctx, idGen, meta)
} else if env == vo.Online {
return r.getOrCreateOnlineStaticConversation(ctx, idGen, meta)
} else {
return 0, 0, false, fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) GetOrCreateDynamicConversation(ctx context.Context, env vo.Env, idGen workflow.ConversationIDGenerator, meta *vo.CreateDynamicConversation) (int64, int64, bool, error) {
if env == vo.Draft {
appDynamicConversationDraft := r.query.AppDynamicConversationDraft
ret, err := appDynamicConversationDraft.WithContext(ctx).Where(
appDynamicConversationDraft.AppID.Eq(meta.AppID),
appDynamicConversationDraft.ConnectorID.Eq(meta.ConnectorID),
appDynamicConversationDraft.UserID.Eq(meta.UserID),
appDynamicConversationDraft.Name.Eq(meta.Name),
).First()
if err == nil {
cInfo, err := crossconversation.DefaultSVC().GetByID(ctx, ret.ConversationID)
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
if cInfo == nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, fmt.Errorf("conversation not found"))
}
return ret.ConversationID, cInfo.SectionID, true, nil
}
if !errors.Is(err, gorm.ErrRecordNotFound) {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
conv, err := idGen(ctx, meta.AppID, meta.UserID, meta.ConnectorID)
if err != nil {
return 0, 0, false, err
}
id, err := r.GenID(ctx)
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrIDGenError, err)
}
err = r.query.AppDynamicConversationDraft.WithContext(ctx).Create(&model.AppDynamicConversationDraft{
ID: id,
AppID: meta.AppID,
Name: meta.Name,
UserID: meta.UserID,
ConnectorID: meta.ConnectorID,
ConversationID: conv.ID,
})
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
return conv.ID, conv.SectionID, false, nil
} else if env == vo.Online {
appDynamicConversationOnline := r.query.AppDynamicConversationOnline
ret, err := appDynamicConversationOnline.WithContext(ctx).Where(
appDynamicConversationOnline.AppID.Eq(meta.AppID),
appDynamicConversationOnline.ConnectorID.Eq(meta.ConnectorID),
appDynamicConversationOnline.UserID.Eq(meta.UserID),
appDynamicConversationOnline.Name.Eq(meta.Name),
).First()
if err == nil {
cInfo, err := crossconversation.DefaultSVC().GetByID(ctx, ret.ConversationID)
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
if cInfo == nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, fmt.Errorf("conversation not found"))
}
return ret.ConversationID, cInfo.SectionID, true, nil
}
if !errors.Is(err, gorm.ErrRecordNotFound) {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
conv, err := idGen(ctx, meta.AppID, meta.UserID, meta.ConnectorID)
if err != nil {
return 0, 0, false, err
}
id, err := r.GenID(ctx)
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrIDGenError, err)
}
err = r.query.AppDynamicConversationOnline.WithContext(ctx).Create(&model.AppDynamicConversationOnline{
ID: id,
AppID: meta.AppID,
Name: meta.Name,
UserID: meta.UserID,
ConnectorID: meta.ConnectorID,
ConversationID: conv.ID,
})
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
return conv.ID, conv.SectionID, false, nil
} else {
return 0, 0, false, fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) GetStaticConversationByTemplateID(ctx context.Context, env vo.Env, userID, connectorID, templateID int64) (*entity.StaticConversation, bool, error) {
if env == vo.Draft {
conditions := make([]gen.Condition, 0, 3)
conditions = append(conditions, r.query.AppStaticConversationDraft.UserID.Eq(userID))
conditions = append(conditions, r.query.AppStaticConversationDraft.ConnectorID.Eq(connectorID))
conditions = append(conditions, r.query.AppStaticConversationDraft.TemplateID.Eq(templateID))
cs, err := r.query.AppStaticConversationDraft.WithContext(ctx).Where(conditions...).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, vo.WrapError(errno.ErrDatabaseError, err)
}
return &entity.StaticConversation{
UserID: cs.UserID,
ConnectorID: cs.ConnectorID,
TemplateID: cs.TemplateID,
ConversationID: cs.ConversationID,
}, true, nil
} else if env == vo.Online {
conditions := make([]gen.Condition, 0, 3)
conditions = append(conditions, r.query.AppStaticConversationOnline.UserID.Eq(userID))
conditions = append(conditions, r.query.AppStaticConversationOnline.ConnectorID.Eq(connectorID))
conditions = append(conditions, r.query.AppStaticConversationOnline.TemplateID.Eq(templateID))
cs, err := r.query.AppStaticConversationOnline.WithContext(ctx).Where(conditions...).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, vo.WrapError(errno.ErrDatabaseError, err)
}
return &entity.StaticConversation{
UserID: cs.UserID,
ConnectorID: cs.ConnectorID,
TemplateID: cs.TemplateID,
ConversationID: cs.ConversationID,
}, true, nil
} else {
return nil, false, fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) getOrCreateDraftStaticConversation(ctx context.Context, idGen workflow.ConversationIDGenerator, meta *vo.CreateStaticConversation) (int64, int64, bool, error) {
cs, err := r.mGetDraftStaticConversation(ctx, meta.UserID, meta.ConnectorID, []int64{meta.TemplateID})
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
if len(cs) > 0 {
cInfo, err := crossconversation.DefaultSVC().GetByID(ctx, cs[0].ConversationID)
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
if cInfo == nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, fmt.Errorf("conversation not found"))
}
return cs[0].ConversationID, cInfo.SectionID, true, nil
}
conv, err := idGen(ctx, meta.AppID, meta.UserID, meta.ConnectorID)
if err != nil {
return 0, 0, false, err
}
id, err := r.GenID(ctx)
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrIDGenError, err)
}
object := &model.AppStaticConversationDraft{
ID: id,
UserID: meta.UserID,
ConnectorID: meta.ConnectorID,
TemplateID: meta.TemplateID,
ConversationID: conv.ID,
}
err = r.query.AppStaticConversationDraft.WithContext(ctx).Create(object)
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
return conv.ID, conv.SectionID, false, nil
}
func (r *RepositoryImpl) getOrCreateOnlineStaticConversation(ctx context.Context, idGen workflow.ConversationIDGenerator, meta *vo.CreateStaticConversation) (int64, int64, bool, error) {
cs, err := r.mGetOnlineStaticConversation(ctx, meta.UserID, meta.ConnectorID, []int64{meta.TemplateID})
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
if len(cs) > 0 {
cInfo, err := crossconversation.DefaultSVC().GetByID(ctx, cs[0].ConversationID)
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
if cInfo == nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, fmt.Errorf("conversation not found"))
}
return cs[0].ConversationID, cInfo.SectionID, true, nil
}
conv, err := idGen(ctx, meta.AppID, meta.UserID, meta.ConnectorID)
if err != nil {
return 0, 0, false, err
}
id, err := r.GenID(ctx)
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrIDGenError, err)
}
object := &model.AppStaticConversationOnline{
ID: id,
UserID: meta.UserID,
ConnectorID: meta.ConnectorID,
TemplateID: meta.TemplateID,
ConversationID: conv.ID,
}
err = r.query.AppStaticConversationOnline.WithContext(ctx).Create(object)
if err != nil {
return 0, 0, false, vo.WrapError(errno.ErrDatabaseError, err)
}
return conv.ID, conv.SectionID, false, nil
}
func (r *RepositoryImpl) BatchCreateOnlineConversationTemplate(ctx context.Context, templates []*entity.ConversationTemplate, version string) error {
ids, err := r.GenMultiIDs(ctx, len(templates))
if err != nil {
return vo.WrapError(errno.ErrIDGenError, err)
}
objects := make([]*model.AppConversationTemplateOnline, 0, len(templates))
for idx := range templates {
template := templates[idx]
objects = append(objects, &model.AppConversationTemplateOnline{
ID: ids[idx],
SpaceID: template.SpaceID,
AppID: template.AppID,
TemplateID: template.TemplateID,
Name: template.Name,
Version: version,
})
}
err = r.query.AppConversationTemplateOnline.WithContext(ctx).CreateInBatches(objects, batchSize)
if err != nil {
return vo.WrapError(errno.ErrDatabaseError, err)
}
return nil
}
func (r *RepositoryImpl) GetDynamicConversationByName(ctx context.Context, env vo.Env, appID, connectorID, userID int64, name string) (*entity.DynamicConversation, bool, error) {
if env == vo.Draft {
appDynamicConversationDraft := r.query.AppDynamicConversationDraft
ret, err := appDynamicConversationDraft.WithContext(ctx).Where(
appDynamicConversationDraft.AppID.Eq(appID),
appDynamicConversationDraft.ConnectorID.Eq(connectorID),
appDynamicConversationDraft.UserID.Eq(userID),
appDynamicConversationDraft.Name.Eq(name)).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
return &entity.DynamicConversation{
ID: ret.ID,
UserID: ret.UserID,
ConnectorID: ret.ConnectorID,
ConversationID: ret.ConversationID,
Name: ret.Name,
}, true, nil
} else if env == vo.Online {
appDynamicConversationOnline := r.query.AppDynamicConversationOnline
ret, err := appDynamicConversationOnline.WithContext(ctx).Where(
appDynamicConversationOnline.AppID.Eq(appID),
appDynamicConversationOnline.ConnectorID.Eq(connectorID),
appDynamicConversationOnline.UserID.Eq(userID),
appDynamicConversationOnline.Name.Eq(name)).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
return &entity.DynamicConversation{
ID: ret.ID,
UserID: ret.UserID,
ConnectorID: ret.ConnectorID,
ConversationID: ret.ConversationID,
Name: ret.Name,
}, true, nil
} else {
return nil, false, fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) UpdateDynamicConversationNameByID(ctx context.Context, env vo.Env, templateID int64, name string) error {
if env == vo.Draft {
appDynamicConversationDraft := r.query.AppDynamicConversationDraft
_, err := appDynamicConversationDraft.WithContext(ctx).Where(
appDynamicConversationDraft.ID.Eq(templateID),
).UpdateColumnSimple(appDynamicConversationDraft.Name.Value(name))
if err != nil {
return vo.WrapError(errno.ErrDatabaseError, err)
}
return nil
} else if env == vo.Online {
appDynamicConversationOnline := r.query.AppDynamicConversationOnline
_, err := appDynamicConversationOnline.WithContext(ctx).Where(
appDynamicConversationOnline.ID.Eq(templateID),
).UpdateColumnSimple(appDynamicConversationOnline.Name.Value(name))
if err != nil {
return vo.WrapError(errno.ErrDatabaseError, err)
}
return nil
} else {
return fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) UpdateStaticConversation(ctx context.Context, env vo.Env, templateID int64, connectorID int64, userID int64, newConversationID int64) error {
if env == vo.Draft {
appStaticConversationDraft := r.query.AppStaticConversationDraft
_, err := appStaticConversationDraft.WithContext(ctx).Where(
appStaticConversationDraft.TemplateID.Eq(templateID),
appStaticConversationDraft.ConnectorID.Eq(connectorID),
appStaticConversationDraft.UserID.Eq(userID),
).UpdateColumn(appStaticConversationDraft.ConversationID, newConversationID)
if err != nil {
return err
}
return err
} else if env == vo.Online {
appStaticConversationOnline := r.query.AppStaticConversationOnline
_, err := appStaticConversationOnline.WithContext(ctx).Where(
appStaticConversationOnline.TemplateID.Eq(templateID),
appStaticConversationOnline.ConnectorID.Eq(connectorID),
appStaticConversationOnline.UserID.Eq(userID),
).UpdateColumn(appStaticConversationOnline.ConversationID, newConversationID)
if err != nil {
return err
}
return nil
} else {
return fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) UpdateDynamicConversation(ctx context.Context, env vo.Env, conversationID, newConversationID int64) error {
if env == vo.Draft {
appDynamicConversationDraft := r.query.AppDynamicConversationDraft
_, err := appDynamicConversationDraft.WithContext(ctx).Where(appDynamicConversationDraft.ConversationID.Eq(conversationID)).
UpdateColumn(appDynamicConversationDraft.ConversationID, newConversationID)
if err != nil {
return err
}
return nil
} else if env == vo.Online {
appDynamicConversationOnline := r.query.AppDynamicConversationOnline
_, err := appDynamicConversationOnline.WithContext(ctx).Where(appDynamicConversationOnline.ConversationID.Eq(conversationID)).
UpdateColumn(appDynamicConversationOnline.ConversationID, newConversationID)
if err != nil {
return err
}
return nil
} else {
return fmt.Errorf("unknown env %v", env)
}
}
func (r *RepositoryImpl) CopyTemplateConversationByAppID(ctx context.Context, appID int64, toAppID int64) error {
appConversationTemplateDraft := r.query.AppConversationTemplateDraft
templates, err := appConversationTemplateDraft.WithContext(ctx).Where(appConversationTemplateDraft.AppID.Eq(appID), appConversationTemplateDraft.Name.Neq("Default")).Find()
if err != nil {
return vo.WrapError(errno.ErrDatabaseError, err)
}
if len(templates) == 0 {
return nil
}
templateTemplates := make([]*model.AppConversationTemplateDraft, 0, len(templates))
ids, err := r.GenMultiIDs(ctx, len(templates))
if err != nil {
return vo.WrapError(errno.ErrIDGenError, err)
}
for i := range templates {
copiedTemplate := templates[i]
copiedTemplate.ID = ids[i]
copiedTemplate.TemplateID = ids[i]
copiedTemplate.AppID = toAppID
templateTemplates = append(templateTemplates, copiedTemplate)
}
err = appConversationTemplateDraft.WithContext(ctx).CreateInBatches(templateTemplates, batchSize)
if err != nil {
return vo.WrapError(errno.ErrDatabaseError, err)
}
return nil
}
func (r *RepositoryImpl) GetStaticConversationByID(ctx context.Context, env vo.Env, appID, connectorID, conversationID int64) (string, bool, error) {
if env == vo.Draft {
appStaticConversationDraft := r.query.AppStaticConversationDraft
ret, err := appStaticConversationDraft.WithContext(ctx).Where(
appStaticConversationDraft.ConnectorID.Eq(connectorID),
appStaticConversationDraft.ConversationID.Eq(conversationID),
).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return "", false, nil
}
return "", false, err
}
appConversationTemplateDraft := r.query.AppConversationTemplateDraft
template, err := appConversationTemplateDraft.WithContext(ctx).Where(
appConversationTemplateDraft.TemplateID.Eq(ret.TemplateID),
appConversationTemplateDraft.AppID.Eq(appID),
).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return "", false, nil
}
return "", false, err
}
return template.Name, true, nil
} else if env == vo.Online {
appStaticConversationOnline := r.query.AppStaticConversationOnline
ret, err := appStaticConversationOnline.WithContext(ctx).Where(
appStaticConversationOnline.ConnectorID.Eq(connectorID),
appStaticConversationOnline.ConversationID.Eq(conversationID),
).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return "", false, nil
}
return "", false, err
}
appConversationTemplateOnline := r.query.AppConversationTemplateOnline
template, err := appConversationTemplateOnline.WithContext(ctx).Where(
appConversationTemplateOnline.TemplateID.Eq(ret.TemplateID),
appConversationTemplateOnline.AppID.Eq(appID),
).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return "", false, nil
}
return "", false, err
}
return template.Name, true, nil
}
return "", false, fmt.Errorf("unknown env %v", env)
}
func (r *RepositoryImpl) GetDynamicConversationByID(ctx context.Context, env vo.Env, appID, connectorID, conversationID int64) (*entity.DynamicConversation, bool, error) {
if env == vo.Draft {
appDynamicConversationDraft := r.query.AppDynamicConversationDraft
ret, err := appDynamicConversationDraft.WithContext(ctx).Where(
appDynamicConversationDraft.AppID.Eq(appID),
appDynamicConversationDraft.ConnectorID.Eq(connectorID),
appDynamicConversationDraft.ConversationID.Eq(conversationID),
).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
return &entity.DynamicConversation{
ID: ret.ID,
UserID: ret.UserID,
ConnectorID: ret.ConnectorID,
ConversationID: ret.ConversationID,
Name: ret.Name,
}, true, nil
} else if env == vo.Online {
appDynamicConversationOnline := r.query.AppDynamicConversationOnline
ret, err := appDynamicConversationOnline.WithContext(ctx).Where(
appDynamicConversationOnline.AppID.Eq(appID),
appDynamicConversationOnline.ConnectorID.Eq(connectorID),
appDynamicConversationOnline.ConversationID.Eq(conversationID),
).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
return &entity.DynamicConversation{
ID: ret.ID,
UserID: ret.UserID,
ConnectorID: ret.ConnectorID,
ConversationID: ret.ConversationID,
Name: ret.Name,
}, true, nil
}
return nil, false, fmt.Errorf("unknown env %v", env)
}

View File

@@ -0,0 +1,29 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"gorm.io/gorm"
)
const TableNameAppConversationTemplateDraft = "app_conversation_template_draft"
// AppConversationTemplateDraft mapped from table <app_conversation_template_draft>
type AppConversationTemplateDraft struct {
ID int64 `gorm:"column:id;primaryKey;comment:id" json:"id"` // id
AppID int64 `gorm:"column:app_id;not null;comment:app id" json:"app_id"` // app id
SpaceID int64 `gorm:"column:space_id;not null;comment:space id" json:"space_id"` // space id
Name string `gorm:"column:name;not null;comment:conversion name" json:"name"` // conversion name
TemplateID int64 `gorm:"column:template_id;not null;comment:template id" json:"template_id"` // template id
CreatorID int64 `gorm:"column:creator_id;not null;comment:creator id" json:"creator_id"` // creator id
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:create time in millisecond" json:"created_at"` // create time in millisecond
UpdatedAt int64 `gorm:"column:updated_at;autoUpdateTime:milli;comment:update time in millisecond" json:"updated_at"` // update time in millisecond
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:delete time in millisecond" json:"deleted_at"` // delete time in millisecond
}
// TableName AppConversationTemplateDraft's table name
func (*AppConversationTemplateDraft) TableName() string {
return TableNameAppConversationTemplateDraft
}

View File

@@ -0,0 +1,24 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
const TableNameAppConversationTemplateOnline = "app_conversation_template_online"
// AppConversationTemplateOnline mapped from table <app_conversation_template_online>
type AppConversationTemplateOnline struct {
ID int64 `gorm:"column:id;primaryKey;comment:id" json:"id"` // id
AppID int64 `gorm:"column:app_id;not null;comment:app id" json:"app_id"` // app id
SpaceID int64 `gorm:"column:space_id;not null;comment:space id" json:"space_id"` // space id
Name string `gorm:"column:name;not null;comment:conversion name" json:"name"` // conversion name
TemplateID int64 `gorm:"column:template_id;not null;comment:template id" json:"template_id"` // template id
Version string `gorm:"column:version;not null;comment:version name" json:"version"` // version name
CreatorID int64 `gorm:"column:creator_id;not null;comment:creator id" json:"creator_id"` // creator id
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:create time in millisecond" json:"created_at"` // create time in millisecond
}
// TableName AppConversationTemplateOnline's table name
func (*AppConversationTemplateOnline) TableName() string {
return TableNameAppConversationTemplateOnline
}

View File

@@ -0,0 +1,28 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"gorm.io/gorm"
)
const TableNameAppDynamicConversationDraft = "app_dynamic_conversation_draft"
// AppDynamicConversationDraft mapped from table <app_dynamic_conversation_draft>
type AppDynamicConversationDraft struct {
ID int64 `gorm:"column:id;primaryKey;comment:id" json:"id"` // id
AppID int64 `gorm:"column:app_id;not null;comment:app id" json:"app_id"` // app id
Name string `gorm:"column:name;not null;comment:conversion name" json:"name"` // conversion name
UserID int64 `gorm:"column:user_id;not null;comment:user id" json:"user_id"` // user id
ConnectorID int64 `gorm:"column:connector_id;not null;comment:connector id" json:"connector_id"` // connector id
ConversationID int64 `gorm:"column:conversation_id;not null;comment:conversation id" json:"conversation_id"` // conversation id
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:create time in millisecond" json:"created_at"` // create time in millisecond
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:delete time in millisecond" json:"deleted_at"` // delete time in millisecond
}
// TableName AppDynamicConversationDraft's table name
func (*AppDynamicConversationDraft) TableName() string {
return TableNameAppDynamicConversationDraft
}

View File

@@ -0,0 +1,28 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"gorm.io/gorm"
)
const TableNameAppDynamicConversationOnline = "app_dynamic_conversation_online"
// AppDynamicConversationOnline mapped from table <app_dynamic_conversation_online>
type AppDynamicConversationOnline struct {
ID int64 `gorm:"column:id;primaryKey;comment:id" json:"id"` // id
AppID int64 `gorm:"column:app_id;not null;comment:app id" json:"app_id"` // app id
Name string `gorm:"column:name;not null;comment:conversion name" json:"name"` // conversion name
UserID int64 `gorm:"column:user_id;not null;comment:user id" json:"user_id"` // user id
ConnectorID int64 `gorm:"column:connector_id;not null;comment:connector id" json:"connector_id"` // connector id
ConversationID int64 `gorm:"column:conversation_id;not null;comment:conversation id" json:"conversation_id"` // conversation id
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:create time in millisecond" json:"created_at"` // create time in millisecond
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:delete time in millisecond" json:"deleted_at"` // delete time in millisecond
}
// TableName AppDynamicConversationOnline's table name
func (*AppDynamicConversationOnline) TableName() string {
return TableNameAppDynamicConversationOnline
}

View File

@@ -0,0 +1,27 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"gorm.io/gorm"
)
const TableNameAppStaticConversationDraft = "app_static_conversation_draft"
// AppStaticConversationDraft mapped from table <app_static_conversation_draft>
type AppStaticConversationDraft struct {
ID int64 `gorm:"column:id;primaryKey;comment:id" json:"id"` // id
TemplateID int64 `gorm:"column:template_id;not null;comment:template id" json:"template_id"` // template id
UserID int64 `gorm:"column:user_id;not null;comment:user id" json:"user_id"` // user id
ConnectorID int64 `gorm:"column:connector_id;not null;comment:connector id" json:"connector_id"` // connector id
ConversationID int64 `gorm:"column:conversation_id;not null;comment:conversation id" json:"conversation_id"` // conversation id
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:create time in millisecond" json:"created_at"` // create time in millisecond
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:delete time in millisecond" json:"deleted_at"` // delete time in millisecond
}
// TableName AppStaticConversationDraft's table name
func (*AppStaticConversationDraft) TableName() string {
return TableNameAppStaticConversationDraft
}

View File

@@ -0,0 +1,22 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
const TableNameAppStaticConversationOnline = "app_static_conversation_online"
// AppStaticConversationOnline mapped from table <app_static_conversation_online>
type AppStaticConversationOnline struct {
ID int64 `gorm:"column:id;primaryKey;comment:id" json:"id"` // id
TemplateID int64 `gorm:"column:template_id;not null;comment:template id" json:"template_id"` // template id
UserID int64 `gorm:"column:user_id;not null;comment:user id" json:"user_id"` // user id
ConnectorID int64 `gorm:"column:connector_id;not null;comment:connector id" json:"connector_id"` // connector id
ConversationID int64 `gorm:"column:conversation_id;not null;comment:conversation id" json:"conversation_id"` // conversation id
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:create time in millisecond" json:"created_at"` // create time in millisecond
}
// TableName AppStaticConversationOnline's table name
func (*AppStaticConversationOnline) TableName() string {
return TableNameAppStaticConversationOnline
}

View File

@@ -0,0 +1,36 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"gorm.io/gorm"
)
const TableNameChatFlowRoleConfig = "chat_flow_role_config"
// ChatFlowRoleConfig mapped from table <chat_flow_role_config>
type ChatFlowRoleConfig struct {
ID int64 `gorm:"column:id;primaryKey;comment:id" json:"id"` // id
WorkflowID int64 `gorm:"column:workflow_id;not null;comment:workflow id" json:"workflow_id"` // workflow id
Name string `gorm:"column:name;not null;comment:role name" json:"name"` // role name
Description string `gorm:"column:description;not null;comment:role description" json:"description"` // role description
Version string `gorm:"column:version;not null;comment:version" json:"version"` // version
Avatar string `gorm:"column:avatar;not null;comment:avatar uri" json:"avatar"` // avatar uri
BackgroundImageInfo string `gorm:"column:background_image_info;not null;comment:background image information, object structure" json:"background_image_info"` // background image information, object structure
OnboardingInfo string `gorm:"column:onboarding_info;not null;comment:intro information, object structure" json:"onboarding_info"` // intro information, object structure
SuggestReplyInfo string `gorm:"column:suggest_reply_info;not null;comment:user suggestions, object structure" json:"suggest_reply_info"` // user suggestions, object structure
AudioConfig string `gorm:"column:audio_config;not null;comment:agent audio config, object structure" json:"audio_config"` // agent audio config, object structure
UserInputConfig string `gorm:"column:user_input_config;not null;comment:user input config, object structure" json:"user_input_config"` // user input config, object structure
CreatorID int64 `gorm:"column:creator_id;not null;comment:creator id" json:"creator_id"` // creator id
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:create time in millisecond" json:"created_at"` // create time in millisecond
UpdatedAt int64 `gorm:"column:updated_at;autoUpdateTime:milli;comment:update time in millisecond" json:"updated_at"` // update time in millisecond
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:delete time in millisecond" json:"deleted_at"` // delete time in millisecond
ConnectorID int64 `gorm:"column:connector_id;comment:connector id" json:"connector_id"` // connector id
}
// TableName ChatFlowRoleConfig's table name
func (*ChatFlowRoleConfig) TableName() string {
return TableNameChatFlowRoleConfig
}

View File

@@ -0,0 +1,412 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo/dal/model"
)
func newAppConversationTemplateDraft(db *gorm.DB, opts ...gen.DOOption) appConversationTemplateDraft {
_appConversationTemplateDraft := appConversationTemplateDraft{}
_appConversationTemplateDraft.appConversationTemplateDraftDo.UseDB(db, opts...)
_appConversationTemplateDraft.appConversationTemplateDraftDo.UseModel(&model.AppConversationTemplateDraft{})
tableName := _appConversationTemplateDraft.appConversationTemplateDraftDo.TableName()
_appConversationTemplateDraft.ALL = field.NewAsterisk(tableName)
_appConversationTemplateDraft.ID = field.NewInt64(tableName, "id")
_appConversationTemplateDraft.AppID = field.NewInt64(tableName, "app_id")
_appConversationTemplateDraft.SpaceID = field.NewInt64(tableName, "space_id")
_appConversationTemplateDraft.Name = field.NewString(tableName, "name")
_appConversationTemplateDraft.TemplateID = field.NewInt64(tableName, "template_id")
_appConversationTemplateDraft.CreatorID = field.NewInt64(tableName, "creator_id")
_appConversationTemplateDraft.CreatedAt = field.NewInt64(tableName, "created_at")
_appConversationTemplateDraft.UpdatedAt = field.NewInt64(tableName, "updated_at")
_appConversationTemplateDraft.DeletedAt = field.NewField(tableName, "deleted_at")
_appConversationTemplateDraft.fillFieldMap()
return _appConversationTemplateDraft
}
type appConversationTemplateDraft struct {
appConversationTemplateDraftDo
ALL field.Asterisk
ID field.Int64 // id
AppID field.Int64 // app id
SpaceID field.Int64 // space id
Name field.String // conversion name
TemplateID field.Int64 // template id
CreatorID field.Int64 // creator id
CreatedAt field.Int64 // create time in millisecond
UpdatedAt field.Int64 // update time in millisecond
DeletedAt field.Field // delete time in millisecond
fieldMap map[string]field.Expr
}
func (a appConversationTemplateDraft) Table(newTableName string) *appConversationTemplateDraft {
a.appConversationTemplateDraftDo.UseTable(newTableName)
return a.updateTableName(newTableName)
}
func (a appConversationTemplateDraft) As(alias string) *appConversationTemplateDraft {
a.appConversationTemplateDraftDo.DO = *(a.appConversationTemplateDraftDo.As(alias).(*gen.DO))
return a.updateTableName(alias)
}
func (a *appConversationTemplateDraft) updateTableName(table string) *appConversationTemplateDraft {
a.ALL = field.NewAsterisk(table)
a.ID = field.NewInt64(table, "id")
a.AppID = field.NewInt64(table, "app_id")
a.SpaceID = field.NewInt64(table, "space_id")
a.Name = field.NewString(table, "name")
a.TemplateID = field.NewInt64(table, "template_id")
a.CreatorID = field.NewInt64(table, "creator_id")
a.CreatedAt = field.NewInt64(table, "created_at")
a.UpdatedAt = field.NewInt64(table, "updated_at")
a.DeletedAt = field.NewField(table, "deleted_at")
a.fillFieldMap()
return a
}
func (a *appConversationTemplateDraft) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := a.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (a *appConversationTemplateDraft) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 9)
a.fieldMap["id"] = a.ID
a.fieldMap["app_id"] = a.AppID
a.fieldMap["space_id"] = a.SpaceID
a.fieldMap["name"] = a.Name
a.fieldMap["template_id"] = a.TemplateID
a.fieldMap["creator_id"] = a.CreatorID
a.fieldMap["created_at"] = a.CreatedAt
a.fieldMap["updated_at"] = a.UpdatedAt
a.fieldMap["deleted_at"] = a.DeletedAt
}
func (a appConversationTemplateDraft) clone(db *gorm.DB) appConversationTemplateDraft {
a.appConversationTemplateDraftDo.ReplaceConnPool(db.Statement.ConnPool)
return a
}
func (a appConversationTemplateDraft) replaceDB(db *gorm.DB) appConversationTemplateDraft {
a.appConversationTemplateDraftDo.ReplaceDB(db)
return a
}
type appConversationTemplateDraftDo struct{ gen.DO }
type IAppConversationTemplateDraftDo interface {
gen.SubQuery
Debug() IAppConversationTemplateDraftDo
WithContext(ctx context.Context) IAppConversationTemplateDraftDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IAppConversationTemplateDraftDo
WriteDB() IAppConversationTemplateDraftDo
As(alias string) gen.Dao
Session(config *gorm.Session) IAppConversationTemplateDraftDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IAppConversationTemplateDraftDo
Not(conds ...gen.Condition) IAppConversationTemplateDraftDo
Or(conds ...gen.Condition) IAppConversationTemplateDraftDo
Select(conds ...field.Expr) IAppConversationTemplateDraftDo
Where(conds ...gen.Condition) IAppConversationTemplateDraftDo
Order(conds ...field.Expr) IAppConversationTemplateDraftDo
Distinct(cols ...field.Expr) IAppConversationTemplateDraftDo
Omit(cols ...field.Expr) IAppConversationTemplateDraftDo
Join(table schema.Tabler, on ...field.Expr) IAppConversationTemplateDraftDo
LeftJoin(table schema.Tabler, on ...field.Expr) IAppConversationTemplateDraftDo
RightJoin(table schema.Tabler, on ...field.Expr) IAppConversationTemplateDraftDo
Group(cols ...field.Expr) IAppConversationTemplateDraftDo
Having(conds ...gen.Condition) IAppConversationTemplateDraftDo
Limit(limit int) IAppConversationTemplateDraftDo
Offset(offset int) IAppConversationTemplateDraftDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IAppConversationTemplateDraftDo
Unscoped() IAppConversationTemplateDraftDo
Create(values ...*model.AppConversationTemplateDraft) error
CreateInBatches(values []*model.AppConversationTemplateDraft, batchSize int) error
Save(values ...*model.AppConversationTemplateDraft) error
First() (*model.AppConversationTemplateDraft, error)
Take() (*model.AppConversationTemplateDraft, error)
Last() (*model.AppConversationTemplateDraft, error)
Find() ([]*model.AppConversationTemplateDraft, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppConversationTemplateDraft, err error)
FindInBatches(result *[]*model.AppConversationTemplateDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.AppConversationTemplateDraft) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IAppConversationTemplateDraftDo
Assign(attrs ...field.AssignExpr) IAppConversationTemplateDraftDo
Joins(fields ...field.RelationField) IAppConversationTemplateDraftDo
Preload(fields ...field.RelationField) IAppConversationTemplateDraftDo
FirstOrInit() (*model.AppConversationTemplateDraft, error)
FirstOrCreate() (*model.AppConversationTemplateDraft, error)
FindByPage(offset int, limit int) (result []*model.AppConversationTemplateDraft, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IAppConversationTemplateDraftDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (a appConversationTemplateDraftDo) Debug() IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Debug())
}
func (a appConversationTemplateDraftDo) WithContext(ctx context.Context) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.WithContext(ctx))
}
func (a appConversationTemplateDraftDo) ReadDB() IAppConversationTemplateDraftDo {
return a.Clauses(dbresolver.Read)
}
func (a appConversationTemplateDraftDo) WriteDB() IAppConversationTemplateDraftDo {
return a.Clauses(dbresolver.Write)
}
func (a appConversationTemplateDraftDo) Session(config *gorm.Session) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Session(config))
}
func (a appConversationTemplateDraftDo) Clauses(conds ...clause.Expression) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Clauses(conds...))
}
func (a appConversationTemplateDraftDo) Returning(value interface{}, columns ...string) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Returning(value, columns...))
}
func (a appConversationTemplateDraftDo) Not(conds ...gen.Condition) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Not(conds...))
}
func (a appConversationTemplateDraftDo) Or(conds ...gen.Condition) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Or(conds...))
}
func (a appConversationTemplateDraftDo) Select(conds ...field.Expr) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Select(conds...))
}
func (a appConversationTemplateDraftDo) Where(conds ...gen.Condition) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Where(conds...))
}
func (a appConversationTemplateDraftDo) Order(conds ...field.Expr) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Order(conds...))
}
func (a appConversationTemplateDraftDo) Distinct(cols ...field.Expr) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Distinct(cols...))
}
func (a appConversationTemplateDraftDo) Omit(cols ...field.Expr) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Omit(cols...))
}
func (a appConversationTemplateDraftDo) Join(table schema.Tabler, on ...field.Expr) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Join(table, on...))
}
func (a appConversationTemplateDraftDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.LeftJoin(table, on...))
}
func (a appConversationTemplateDraftDo) RightJoin(table schema.Tabler, on ...field.Expr) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.RightJoin(table, on...))
}
func (a appConversationTemplateDraftDo) Group(cols ...field.Expr) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Group(cols...))
}
func (a appConversationTemplateDraftDo) Having(conds ...gen.Condition) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Having(conds...))
}
func (a appConversationTemplateDraftDo) Limit(limit int) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Limit(limit))
}
func (a appConversationTemplateDraftDo) Offset(offset int) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Offset(offset))
}
func (a appConversationTemplateDraftDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Scopes(funcs...))
}
func (a appConversationTemplateDraftDo) Unscoped() IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Unscoped())
}
func (a appConversationTemplateDraftDo) Create(values ...*model.AppConversationTemplateDraft) error {
if len(values) == 0 {
return nil
}
return a.DO.Create(values)
}
func (a appConversationTemplateDraftDo) CreateInBatches(values []*model.AppConversationTemplateDraft, batchSize int) error {
return a.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (a appConversationTemplateDraftDo) Save(values ...*model.AppConversationTemplateDraft) error {
if len(values) == 0 {
return nil
}
return a.DO.Save(values)
}
func (a appConversationTemplateDraftDo) First() (*model.AppConversationTemplateDraft, error) {
if result, err := a.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.AppConversationTemplateDraft), nil
}
}
func (a appConversationTemplateDraftDo) Take() (*model.AppConversationTemplateDraft, error) {
if result, err := a.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.AppConversationTemplateDraft), nil
}
}
func (a appConversationTemplateDraftDo) Last() (*model.AppConversationTemplateDraft, error) {
if result, err := a.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.AppConversationTemplateDraft), nil
}
}
func (a appConversationTemplateDraftDo) Find() ([]*model.AppConversationTemplateDraft, error) {
result, err := a.DO.Find()
return result.([]*model.AppConversationTemplateDraft), err
}
func (a appConversationTemplateDraftDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppConversationTemplateDraft, err error) {
buf := make([]*model.AppConversationTemplateDraft, 0, batchSize)
err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (a appConversationTemplateDraftDo) FindInBatches(result *[]*model.AppConversationTemplateDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return a.DO.FindInBatches(result, batchSize, fc)
}
func (a appConversationTemplateDraftDo) Attrs(attrs ...field.AssignExpr) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Attrs(attrs...))
}
func (a appConversationTemplateDraftDo) Assign(attrs ...field.AssignExpr) IAppConversationTemplateDraftDo {
return a.withDO(a.DO.Assign(attrs...))
}
func (a appConversationTemplateDraftDo) Joins(fields ...field.RelationField) IAppConversationTemplateDraftDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Joins(_f))
}
return &a
}
func (a appConversationTemplateDraftDo) Preload(fields ...field.RelationField) IAppConversationTemplateDraftDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Preload(_f))
}
return &a
}
func (a appConversationTemplateDraftDo) FirstOrInit() (*model.AppConversationTemplateDraft, error) {
if result, err := a.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.AppConversationTemplateDraft), nil
}
}
func (a appConversationTemplateDraftDo) FirstOrCreate() (*model.AppConversationTemplateDraft, error) {
if result, err := a.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.AppConversationTemplateDraft), nil
}
}
func (a appConversationTemplateDraftDo) FindByPage(offset int, limit int) (result []*model.AppConversationTemplateDraft, count int64, err error) {
result, err = a.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = a.Offset(-1).Limit(-1).Count()
return
}
func (a appConversationTemplateDraftDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = a.Count()
if err != nil {
return
}
err = a.Offset(offset).Limit(limit).Scan(result)
return
}
func (a appConversationTemplateDraftDo) Scan(result interface{}) (err error) {
return a.DO.Scan(result)
}
func (a appConversationTemplateDraftDo) Delete(models ...*model.AppConversationTemplateDraft) (result gen.ResultInfo, err error) {
return a.DO.Delete(models)
}
func (a *appConversationTemplateDraftDo) withDO(do gen.Dao) *appConversationTemplateDraftDo {
a.DO = *do.(*gen.DO)
return a
}

View File

@@ -0,0 +1,408 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo/dal/model"
)
func newAppConversationTemplateOnline(db *gorm.DB, opts ...gen.DOOption) appConversationTemplateOnline {
_appConversationTemplateOnline := appConversationTemplateOnline{}
_appConversationTemplateOnline.appConversationTemplateOnlineDo.UseDB(db, opts...)
_appConversationTemplateOnline.appConversationTemplateOnlineDo.UseModel(&model.AppConversationTemplateOnline{})
tableName := _appConversationTemplateOnline.appConversationTemplateOnlineDo.TableName()
_appConversationTemplateOnline.ALL = field.NewAsterisk(tableName)
_appConversationTemplateOnline.ID = field.NewInt64(tableName, "id")
_appConversationTemplateOnline.AppID = field.NewInt64(tableName, "app_id")
_appConversationTemplateOnline.SpaceID = field.NewInt64(tableName, "space_id")
_appConversationTemplateOnline.Name = field.NewString(tableName, "name")
_appConversationTemplateOnline.TemplateID = field.NewInt64(tableName, "template_id")
_appConversationTemplateOnline.Version = field.NewString(tableName, "version")
_appConversationTemplateOnline.CreatorID = field.NewInt64(tableName, "creator_id")
_appConversationTemplateOnline.CreatedAt = field.NewInt64(tableName, "created_at")
_appConversationTemplateOnline.fillFieldMap()
return _appConversationTemplateOnline
}
type appConversationTemplateOnline struct {
appConversationTemplateOnlineDo
ALL field.Asterisk
ID field.Int64 // id
AppID field.Int64 // app id
SpaceID field.Int64 // space id
Name field.String // conversion name
TemplateID field.Int64 // template id
Version field.String // version name
CreatorID field.Int64 // creator id
CreatedAt field.Int64 // create time in millisecond
fieldMap map[string]field.Expr
}
func (a appConversationTemplateOnline) Table(newTableName string) *appConversationTemplateOnline {
a.appConversationTemplateOnlineDo.UseTable(newTableName)
return a.updateTableName(newTableName)
}
func (a appConversationTemplateOnline) As(alias string) *appConversationTemplateOnline {
a.appConversationTemplateOnlineDo.DO = *(a.appConversationTemplateOnlineDo.As(alias).(*gen.DO))
return a.updateTableName(alias)
}
func (a *appConversationTemplateOnline) updateTableName(table string) *appConversationTemplateOnline {
a.ALL = field.NewAsterisk(table)
a.ID = field.NewInt64(table, "id")
a.AppID = field.NewInt64(table, "app_id")
a.SpaceID = field.NewInt64(table, "space_id")
a.Name = field.NewString(table, "name")
a.TemplateID = field.NewInt64(table, "template_id")
a.Version = field.NewString(table, "version")
a.CreatorID = field.NewInt64(table, "creator_id")
a.CreatedAt = field.NewInt64(table, "created_at")
a.fillFieldMap()
return a
}
func (a *appConversationTemplateOnline) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := a.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (a *appConversationTemplateOnline) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 8)
a.fieldMap["id"] = a.ID
a.fieldMap["app_id"] = a.AppID
a.fieldMap["space_id"] = a.SpaceID
a.fieldMap["name"] = a.Name
a.fieldMap["template_id"] = a.TemplateID
a.fieldMap["version"] = a.Version
a.fieldMap["creator_id"] = a.CreatorID
a.fieldMap["created_at"] = a.CreatedAt
}
func (a appConversationTemplateOnline) clone(db *gorm.DB) appConversationTemplateOnline {
a.appConversationTemplateOnlineDo.ReplaceConnPool(db.Statement.ConnPool)
return a
}
func (a appConversationTemplateOnline) replaceDB(db *gorm.DB) appConversationTemplateOnline {
a.appConversationTemplateOnlineDo.ReplaceDB(db)
return a
}
type appConversationTemplateOnlineDo struct{ gen.DO }
type IAppConversationTemplateOnlineDo interface {
gen.SubQuery
Debug() IAppConversationTemplateOnlineDo
WithContext(ctx context.Context) IAppConversationTemplateOnlineDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IAppConversationTemplateOnlineDo
WriteDB() IAppConversationTemplateOnlineDo
As(alias string) gen.Dao
Session(config *gorm.Session) IAppConversationTemplateOnlineDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IAppConversationTemplateOnlineDo
Not(conds ...gen.Condition) IAppConversationTemplateOnlineDo
Or(conds ...gen.Condition) IAppConversationTemplateOnlineDo
Select(conds ...field.Expr) IAppConversationTemplateOnlineDo
Where(conds ...gen.Condition) IAppConversationTemplateOnlineDo
Order(conds ...field.Expr) IAppConversationTemplateOnlineDo
Distinct(cols ...field.Expr) IAppConversationTemplateOnlineDo
Omit(cols ...field.Expr) IAppConversationTemplateOnlineDo
Join(table schema.Tabler, on ...field.Expr) IAppConversationTemplateOnlineDo
LeftJoin(table schema.Tabler, on ...field.Expr) IAppConversationTemplateOnlineDo
RightJoin(table schema.Tabler, on ...field.Expr) IAppConversationTemplateOnlineDo
Group(cols ...field.Expr) IAppConversationTemplateOnlineDo
Having(conds ...gen.Condition) IAppConversationTemplateOnlineDo
Limit(limit int) IAppConversationTemplateOnlineDo
Offset(offset int) IAppConversationTemplateOnlineDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IAppConversationTemplateOnlineDo
Unscoped() IAppConversationTemplateOnlineDo
Create(values ...*model.AppConversationTemplateOnline) error
CreateInBatches(values []*model.AppConversationTemplateOnline, batchSize int) error
Save(values ...*model.AppConversationTemplateOnline) error
First() (*model.AppConversationTemplateOnline, error)
Take() (*model.AppConversationTemplateOnline, error)
Last() (*model.AppConversationTemplateOnline, error)
Find() ([]*model.AppConversationTemplateOnline, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppConversationTemplateOnline, err error)
FindInBatches(result *[]*model.AppConversationTemplateOnline, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.AppConversationTemplateOnline) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IAppConversationTemplateOnlineDo
Assign(attrs ...field.AssignExpr) IAppConversationTemplateOnlineDo
Joins(fields ...field.RelationField) IAppConversationTemplateOnlineDo
Preload(fields ...field.RelationField) IAppConversationTemplateOnlineDo
FirstOrInit() (*model.AppConversationTemplateOnline, error)
FirstOrCreate() (*model.AppConversationTemplateOnline, error)
FindByPage(offset int, limit int) (result []*model.AppConversationTemplateOnline, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IAppConversationTemplateOnlineDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (a appConversationTemplateOnlineDo) Debug() IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Debug())
}
func (a appConversationTemplateOnlineDo) WithContext(ctx context.Context) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.WithContext(ctx))
}
func (a appConversationTemplateOnlineDo) ReadDB() IAppConversationTemplateOnlineDo {
return a.Clauses(dbresolver.Read)
}
func (a appConversationTemplateOnlineDo) WriteDB() IAppConversationTemplateOnlineDo {
return a.Clauses(dbresolver.Write)
}
func (a appConversationTemplateOnlineDo) Session(config *gorm.Session) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Session(config))
}
func (a appConversationTemplateOnlineDo) Clauses(conds ...clause.Expression) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Clauses(conds...))
}
func (a appConversationTemplateOnlineDo) Returning(value interface{}, columns ...string) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Returning(value, columns...))
}
func (a appConversationTemplateOnlineDo) Not(conds ...gen.Condition) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Not(conds...))
}
func (a appConversationTemplateOnlineDo) Or(conds ...gen.Condition) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Or(conds...))
}
func (a appConversationTemplateOnlineDo) Select(conds ...field.Expr) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Select(conds...))
}
func (a appConversationTemplateOnlineDo) Where(conds ...gen.Condition) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Where(conds...))
}
func (a appConversationTemplateOnlineDo) Order(conds ...field.Expr) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Order(conds...))
}
func (a appConversationTemplateOnlineDo) Distinct(cols ...field.Expr) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Distinct(cols...))
}
func (a appConversationTemplateOnlineDo) Omit(cols ...field.Expr) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Omit(cols...))
}
func (a appConversationTemplateOnlineDo) Join(table schema.Tabler, on ...field.Expr) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Join(table, on...))
}
func (a appConversationTemplateOnlineDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.LeftJoin(table, on...))
}
func (a appConversationTemplateOnlineDo) RightJoin(table schema.Tabler, on ...field.Expr) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.RightJoin(table, on...))
}
func (a appConversationTemplateOnlineDo) Group(cols ...field.Expr) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Group(cols...))
}
func (a appConversationTemplateOnlineDo) Having(conds ...gen.Condition) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Having(conds...))
}
func (a appConversationTemplateOnlineDo) Limit(limit int) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Limit(limit))
}
func (a appConversationTemplateOnlineDo) Offset(offset int) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Offset(offset))
}
func (a appConversationTemplateOnlineDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Scopes(funcs...))
}
func (a appConversationTemplateOnlineDo) Unscoped() IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Unscoped())
}
func (a appConversationTemplateOnlineDo) Create(values ...*model.AppConversationTemplateOnline) error {
if len(values) == 0 {
return nil
}
return a.DO.Create(values)
}
func (a appConversationTemplateOnlineDo) CreateInBatches(values []*model.AppConversationTemplateOnline, batchSize int) error {
return a.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (a appConversationTemplateOnlineDo) Save(values ...*model.AppConversationTemplateOnline) error {
if len(values) == 0 {
return nil
}
return a.DO.Save(values)
}
func (a appConversationTemplateOnlineDo) First() (*model.AppConversationTemplateOnline, error) {
if result, err := a.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.AppConversationTemplateOnline), nil
}
}
func (a appConversationTemplateOnlineDo) Take() (*model.AppConversationTemplateOnline, error) {
if result, err := a.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.AppConversationTemplateOnline), nil
}
}
func (a appConversationTemplateOnlineDo) Last() (*model.AppConversationTemplateOnline, error) {
if result, err := a.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.AppConversationTemplateOnline), nil
}
}
func (a appConversationTemplateOnlineDo) Find() ([]*model.AppConversationTemplateOnline, error) {
result, err := a.DO.Find()
return result.([]*model.AppConversationTemplateOnline), err
}
func (a appConversationTemplateOnlineDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppConversationTemplateOnline, err error) {
buf := make([]*model.AppConversationTemplateOnline, 0, batchSize)
err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (a appConversationTemplateOnlineDo) FindInBatches(result *[]*model.AppConversationTemplateOnline, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return a.DO.FindInBatches(result, batchSize, fc)
}
func (a appConversationTemplateOnlineDo) Attrs(attrs ...field.AssignExpr) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Attrs(attrs...))
}
func (a appConversationTemplateOnlineDo) Assign(attrs ...field.AssignExpr) IAppConversationTemplateOnlineDo {
return a.withDO(a.DO.Assign(attrs...))
}
func (a appConversationTemplateOnlineDo) Joins(fields ...field.RelationField) IAppConversationTemplateOnlineDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Joins(_f))
}
return &a
}
func (a appConversationTemplateOnlineDo) Preload(fields ...field.RelationField) IAppConversationTemplateOnlineDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Preload(_f))
}
return &a
}
func (a appConversationTemplateOnlineDo) FirstOrInit() (*model.AppConversationTemplateOnline, error) {
if result, err := a.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.AppConversationTemplateOnline), nil
}
}
func (a appConversationTemplateOnlineDo) FirstOrCreate() (*model.AppConversationTemplateOnline, error) {
if result, err := a.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.AppConversationTemplateOnline), nil
}
}
func (a appConversationTemplateOnlineDo) FindByPage(offset int, limit int) (result []*model.AppConversationTemplateOnline, count int64, err error) {
result, err = a.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = a.Offset(-1).Limit(-1).Count()
return
}
func (a appConversationTemplateOnlineDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = a.Count()
if err != nil {
return
}
err = a.Offset(offset).Limit(limit).Scan(result)
return
}
func (a appConversationTemplateOnlineDo) Scan(result interface{}) (err error) {
return a.DO.Scan(result)
}
func (a appConversationTemplateOnlineDo) Delete(models ...*model.AppConversationTemplateOnline) (result gen.ResultInfo, err error) {
return a.DO.Delete(models)
}
func (a *appConversationTemplateOnlineDo) withDO(do gen.Dao) *appConversationTemplateOnlineDo {
a.DO = *do.(*gen.DO)
return a
}

View File

@@ -0,0 +1,408 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo/dal/model"
)
func newAppDynamicConversationDraft(db *gorm.DB, opts ...gen.DOOption) appDynamicConversationDraft {
_appDynamicConversationDraft := appDynamicConversationDraft{}
_appDynamicConversationDraft.appDynamicConversationDraftDo.UseDB(db, opts...)
_appDynamicConversationDraft.appDynamicConversationDraftDo.UseModel(&model.AppDynamicConversationDraft{})
tableName := _appDynamicConversationDraft.appDynamicConversationDraftDo.TableName()
_appDynamicConversationDraft.ALL = field.NewAsterisk(tableName)
_appDynamicConversationDraft.ID = field.NewInt64(tableName, "id")
_appDynamicConversationDraft.AppID = field.NewInt64(tableName, "app_id")
_appDynamicConversationDraft.Name = field.NewString(tableName, "name")
_appDynamicConversationDraft.UserID = field.NewInt64(tableName, "user_id")
_appDynamicConversationDraft.ConnectorID = field.NewInt64(tableName, "connector_id")
_appDynamicConversationDraft.ConversationID = field.NewInt64(tableName, "conversation_id")
_appDynamicConversationDraft.CreatedAt = field.NewInt64(tableName, "created_at")
_appDynamicConversationDraft.DeletedAt = field.NewField(tableName, "deleted_at")
_appDynamicConversationDraft.fillFieldMap()
return _appDynamicConversationDraft
}
type appDynamicConversationDraft struct {
appDynamicConversationDraftDo
ALL field.Asterisk
ID field.Int64 // id
AppID field.Int64 // app id
Name field.String // conversion name
UserID field.Int64 // user id
ConnectorID field.Int64 // connector id
ConversationID field.Int64 // conversation id
CreatedAt field.Int64 // create time in millisecond
DeletedAt field.Field // delete time in millisecond
fieldMap map[string]field.Expr
}
func (a appDynamicConversationDraft) Table(newTableName string) *appDynamicConversationDraft {
a.appDynamicConversationDraftDo.UseTable(newTableName)
return a.updateTableName(newTableName)
}
func (a appDynamicConversationDraft) As(alias string) *appDynamicConversationDraft {
a.appDynamicConversationDraftDo.DO = *(a.appDynamicConversationDraftDo.As(alias).(*gen.DO))
return a.updateTableName(alias)
}
func (a *appDynamicConversationDraft) updateTableName(table string) *appDynamicConversationDraft {
a.ALL = field.NewAsterisk(table)
a.ID = field.NewInt64(table, "id")
a.AppID = field.NewInt64(table, "app_id")
a.Name = field.NewString(table, "name")
a.UserID = field.NewInt64(table, "user_id")
a.ConnectorID = field.NewInt64(table, "connector_id")
a.ConversationID = field.NewInt64(table, "conversation_id")
a.CreatedAt = field.NewInt64(table, "created_at")
a.DeletedAt = field.NewField(table, "deleted_at")
a.fillFieldMap()
return a
}
func (a *appDynamicConversationDraft) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := a.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (a *appDynamicConversationDraft) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 8)
a.fieldMap["id"] = a.ID
a.fieldMap["app_id"] = a.AppID
a.fieldMap["name"] = a.Name
a.fieldMap["user_id"] = a.UserID
a.fieldMap["connector_id"] = a.ConnectorID
a.fieldMap["conversation_id"] = a.ConversationID
a.fieldMap["created_at"] = a.CreatedAt
a.fieldMap["deleted_at"] = a.DeletedAt
}
func (a appDynamicConversationDraft) clone(db *gorm.DB) appDynamicConversationDraft {
a.appDynamicConversationDraftDo.ReplaceConnPool(db.Statement.ConnPool)
return a
}
func (a appDynamicConversationDraft) replaceDB(db *gorm.DB) appDynamicConversationDraft {
a.appDynamicConversationDraftDo.ReplaceDB(db)
return a
}
type appDynamicConversationDraftDo struct{ gen.DO }
type IAppDynamicConversationDraftDo interface {
gen.SubQuery
Debug() IAppDynamicConversationDraftDo
WithContext(ctx context.Context) IAppDynamicConversationDraftDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IAppDynamicConversationDraftDo
WriteDB() IAppDynamicConversationDraftDo
As(alias string) gen.Dao
Session(config *gorm.Session) IAppDynamicConversationDraftDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IAppDynamicConversationDraftDo
Not(conds ...gen.Condition) IAppDynamicConversationDraftDo
Or(conds ...gen.Condition) IAppDynamicConversationDraftDo
Select(conds ...field.Expr) IAppDynamicConversationDraftDo
Where(conds ...gen.Condition) IAppDynamicConversationDraftDo
Order(conds ...field.Expr) IAppDynamicConversationDraftDo
Distinct(cols ...field.Expr) IAppDynamicConversationDraftDo
Omit(cols ...field.Expr) IAppDynamicConversationDraftDo
Join(table schema.Tabler, on ...field.Expr) IAppDynamicConversationDraftDo
LeftJoin(table schema.Tabler, on ...field.Expr) IAppDynamicConversationDraftDo
RightJoin(table schema.Tabler, on ...field.Expr) IAppDynamicConversationDraftDo
Group(cols ...field.Expr) IAppDynamicConversationDraftDo
Having(conds ...gen.Condition) IAppDynamicConversationDraftDo
Limit(limit int) IAppDynamicConversationDraftDo
Offset(offset int) IAppDynamicConversationDraftDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IAppDynamicConversationDraftDo
Unscoped() IAppDynamicConversationDraftDo
Create(values ...*model.AppDynamicConversationDraft) error
CreateInBatches(values []*model.AppDynamicConversationDraft, batchSize int) error
Save(values ...*model.AppDynamicConversationDraft) error
First() (*model.AppDynamicConversationDraft, error)
Take() (*model.AppDynamicConversationDraft, error)
Last() (*model.AppDynamicConversationDraft, error)
Find() ([]*model.AppDynamicConversationDraft, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppDynamicConversationDraft, err error)
FindInBatches(result *[]*model.AppDynamicConversationDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.AppDynamicConversationDraft) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IAppDynamicConversationDraftDo
Assign(attrs ...field.AssignExpr) IAppDynamicConversationDraftDo
Joins(fields ...field.RelationField) IAppDynamicConversationDraftDo
Preload(fields ...field.RelationField) IAppDynamicConversationDraftDo
FirstOrInit() (*model.AppDynamicConversationDraft, error)
FirstOrCreate() (*model.AppDynamicConversationDraft, error)
FindByPage(offset int, limit int) (result []*model.AppDynamicConversationDraft, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IAppDynamicConversationDraftDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (a appDynamicConversationDraftDo) Debug() IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Debug())
}
func (a appDynamicConversationDraftDo) WithContext(ctx context.Context) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.WithContext(ctx))
}
func (a appDynamicConversationDraftDo) ReadDB() IAppDynamicConversationDraftDo {
return a.Clauses(dbresolver.Read)
}
func (a appDynamicConversationDraftDo) WriteDB() IAppDynamicConversationDraftDo {
return a.Clauses(dbresolver.Write)
}
func (a appDynamicConversationDraftDo) Session(config *gorm.Session) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Session(config))
}
func (a appDynamicConversationDraftDo) Clauses(conds ...clause.Expression) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Clauses(conds...))
}
func (a appDynamicConversationDraftDo) Returning(value interface{}, columns ...string) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Returning(value, columns...))
}
func (a appDynamicConversationDraftDo) Not(conds ...gen.Condition) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Not(conds...))
}
func (a appDynamicConversationDraftDo) Or(conds ...gen.Condition) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Or(conds...))
}
func (a appDynamicConversationDraftDo) Select(conds ...field.Expr) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Select(conds...))
}
func (a appDynamicConversationDraftDo) Where(conds ...gen.Condition) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Where(conds...))
}
func (a appDynamicConversationDraftDo) Order(conds ...field.Expr) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Order(conds...))
}
func (a appDynamicConversationDraftDo) Distinct(cols ...field.Expr) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Distinct(cols...))
}
func (a appDynamicConversationDraftDo) Omit(cols ...field.Expr) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Omit(cols...))
}
func (a appDynamicConversationDraftDo) Join(table schema.Tabler, on ...field.Expr) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Join(table, on...))
}
func (a appDynamicConversationDraftDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.LeftJoin(table, on...))
}
func (a appDynamicConversationDraftDo) RightJoin(table schema.Tabler, on ...field.Expr) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.RightJoin(table, on...))
}
func (a appDynamicConversationDraftDo) Group(cols ...field.Expr) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Group(cols...))
}
func (a appDynamicConversationDraftDo) Having(conds ...gen.Condition) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Having(conds...))
}
func (a appDynamicConversationDraftDo) Limit(limit int) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Limit(limit))
}
func (a appDynamicConversationDraftDo) Offset(offset int) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Offset(offset))
}
func (a appDynamicConversationDraftDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Scopes(funcs...))
}
func (a appDynamicConversationDraftDo) Unscoped() IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Unscoped())
}
func (a appDynamicConversationDraftDo) Create(values ...*model.AppDynamicConversationDraft) error {
if len(values) == 0 {
return nil
}
return a.DO.Create(values)
}
func (a appDynamicConversationDraftDo) CreateInBatches(values []*model.AppDynamicConversationDraft, batchSize int) error {
return a.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (a appDynamicConversationDraftDo) Save(values ...*model.AppDynamicConversationDraft) error {
if len(values) == 0 {
return nil
}
return a.DO.Save(values)
}
func (a appDynamicConversationDraftDo) First() (*model.AppDynamicConversationDraft, error) {
if result, err := a.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.AppDynamicConversationDraft), nil
}
}
func (a appDynamicConversationDraftDo) Take() (*model.AppDynamicConversationDraft, error) {
if result, err := a.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.AppDynamicConversationDraft), nil
}
}
func (a appDynamicConversationDraftDo) Last() (*model.AppDynamicConversationDraft, error) {
if result, err := a.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.AppDynamicConversationDraft), nil
}
}
func (a appDynamicConversationDraftDo) Find() ([]*model.AppDynamicConversationDraft, error) {
result, err := a.DO.Find()
return result.([]*model.AppDynamicConversationDraft), err
}
func (a appDynamicConversationDraftDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppDynamicConversationDraft, err error) {
buf := make([]*model.AppDynamicConversationDraft, 0, batchSize)
err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (a appDynamicConversationDraftDo) FindInBatches(result *[]*model.AppDynamicConversationDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return a.DO.FindInBatches(result, batchSize, fc)
}
func (a appDynamicConversationDraftDo) Attrs(attrs ...field.AssignExpr) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Attrs(attrs...))
}
func (a appDynamicConversationDraftDo) Assign(attrs ...field.AssignExpr) IAppDynamicConversationDraftDo {
return a.withDO(a.DO.Assign(attrs...))
}
func (a appDynamicConversationDraftDo) Joins(fields ...field.RelationField) IAppDynamicConversationDraftDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Joins(_f))
}
return &a
}
func (a appDynamicConversationDraftDo) Preload(fields ...field.RelationField) IAppDynamicConversationDraftDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Preload(_f))
}
return &a
}
func (a appDynamicConversationDraftDo) FirstOrInit() (*model.AppDynamicConversationDraft, error) {
if result, err := a.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.AppDynamicConversationDraft), nil
}
}
func (a appDynamicConversationDraftDo) FirstOrCreate() (*model.AppDynamicConversationDraft, error) {
if result, err := a.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.AppDynamicConversationDraft), nil
}
}
func (a appDynamicConversationDraftDo) FindByPage(offset int, limit int) (result []*model.AppDynamicConversationDraft, count int64, err error) {
result, err = a.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = a.Offset(-1).Limit(-1).Count()
return
}
func (a appDynamicConversationDraftDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = a.Count()
if err != nil {
return
}
err = a.Offset(offset).Limit(limit).Scan(result)
return
}
func (a appDynamicConversationDraftDo) Scan(result interface{}) (err error) {
return a.DO.Scan(result)
}
func (a appDynamicConversationDraftDo) Delete(models ...*model.AppDynamicConversationDraft) (result gen.ResultInfo, err error) {
return a.DO.Delete(models)
}
func (a *appDynamicConversationDraftDo) withDO(do gen.Dao) *appDynamicConversationDraftDo {
a.DO = *do.(*gen.DO)
return a
}

View File

@@ -0,0 +1,408 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo/dal/model"
)
func newAppDynamicConversationOnline(db *gorm.DB, opts ...gen.DOOption) appDynamicConversationOnline {
_appDynamicConversationOnline := appDynamicConversationOnline{}
_appDynamicConversationOnline.appDynamicConversationOnlineDo.UseDB(db, opts...)
_appDynamicConversationOnline.appDynamicConversationOnlineDo.UseModel(&model.AppDynamicConversationOnline{})
tableName := _appDynamicConversationOnline.appDynamicConversationOnlineDo.TableName()
_appDynamicConversationOnline.ALL = field.NewAsterisk(tableName)
_appDynamicConversationOnline.ID = field.NewInt64(tableName, "id")
_appDynamicConversationOnline.AppID = field.NewInt64(tableName, "app_id")
_appDynamicConversationOnline.Name = field.NewString(tableName, "name")
_appDynamicConversationOnline.UserID = field.NewInt64(tableName, "user_id")
_appDynamicConversationOnline.ConnectorID = field.NewInt64(tableName, "connector_id")
_appDynamicConversationOnline.ConversationID = field.NewInt64(tableName, "conversation_id")
_appDynamicConversationOnline.CreatedAt = field.NewInt64(tableName, "created_at")
_appDynamicConversationOnline.DeletedAt = field.NewField(tableName, "deleted_at")
_appDynamicConversationOnline.fillFieldMap()
return _appDynamicConversationOnline
}
type appDynamicConversationOnline struct {
appDynamicConversationOnlineDo
ALL field.Asterisk
ID field.Int64 // id
AppID field.Int64 // app id
Name field.String // conversion name
UserID field.Int64 // user id
ConnectorID field.Int64 // connector id
ConversationID field.Int64 // conversation id
CreatedAt field.Int64 // create time in millisecond
DeletedAt field.Field // delete time in millisecond
fieldMap map[string]field.Expr
}
func (a appDynamicConversationOnline) Table(newTableName string) *appDynamicConversationOnline {
a.appDynamicConversationOnlineDo.UseTable(newTableName)
return a.updateTableName(newTableName)
}
func (a appDynamicConversationOnline) As(alias string) *appDynamicConversationOnline {
a.appDynamicConversationOnlineDo.DO = *(a.appDynamicConversationOnlineDo.As(alias).(*gen.DO))
return a.updateTableName(alias)
}
func (a *appDynamicConversationOnline) updateTableName(table string) *appDynamicConversationOnline {
a.ALL = field.NewAsterisk(table)
a.ID = field.NewInt64(table, "id")
a.AppID = field.NewInt64(table, "app_id")
a.Name = field.NewString(table, "name")
a.UserID = field.NewInt64(table, "user_id")
a.ConnectorID = field.NewInt64(table, "connector_id")
a.ConversationID = field.NewInt64(table, "conversation_id")
a.CreatedAt = field.NewInt64(table, "created_at")
a.DeletedAt = field.NewField(table, "deleted_at")
a.fillFieldMap()
return a
}
func (a *appDynamicConversationOnline) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := a.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (a *appDynamicConversationOnline) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 8)
a.fieldMap["id"] = a.ID
a.fieldMap["app_id"] = a.AppID
a.fieldMap["name"] = a.Name
a.fieldMap["user_id"] = a.UserID
a.fieldMap["connector_id"] = a.ConnectorID
a.fieldMap["conversation_id"] = a.ConversationID
a.fieldMap["created_at"] = a.CreatedAt
a.fieldMap["deleted_at"] = a.DeletedAt
}
func (a appDynamicConversationOnline) clone(db *gorm.DB) appDynamicConversationOnline {
a.appDynamicConversationOnlineDo.ReplaceConnPool(db.Statement.ConnPool)
return a
}
func (a appDynamicConversationOnline) replaceDB(db *gorm.DB) appDynamicConversationOnline {
a.appDynamicConversationOnlineDo.ReplaceDB(db)
return a
}
type appDynamicConversationOnlineDo struct{ gen.DO }
type IAppDynamicConversationOnlineDo interface {
gen.SubQuery
Debug() IAppDynamicConversationOnlineDo
WithContext(ctx context.Context) IAppDynamicConversationOnlineDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IAppDynamicConversationOnlineDo
WriteDB() IAppDynamicConversationOnlineDo
As(alias string) gen.Dao
Session(config *gorm.Session) IAppDynamicConversationOnlineDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IAppDynamicConversationOnlineDo
Not(conds ...gen.Condition) IAppDynamicConversationOnlineDo
Or(conds ...gen.Condition) IAppDynamicConversationOnlineDo
Select(conds ...field.Expr) IAppDynamicConversationOnlineDo
Where(conds ...gen.Condition) IAppDynamicConversationOnlineDo
Order(conds ...field.Expr) IAppDynamicConversationOnlineDo
Distinct(cols ...field.Expr) IAppDynamicConversationOnlineDo
Omit(cols ...field.Expr) IAppDynamicConversationOnlineDo
Join(table schema.Tabler, on ...field.Expr) IAppDynamicConversationOnlineDo
LeftJoin(table schema.Tabler, on ...field.Expr) IAppDynamicConversationOnlineDo
RightJoin(table schema.Tabler, on ...field.Expr) IAppDynamicConversationOnlineDo
Group(cols ...field.Expr) IAppDynamicConversationOnlineDo
Having(conds ...gen.Condition) IAppDynamicConversationOnlineDo
Limit(limit int) IAppDynamicConversationOnlineDo
Offset(offset int) IAppDynamicConversationOnlineDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IAppDynamicConversationOnlineDo
Unscoped() IAppDynamicConversationOnlineDo
Create(values ...*model.AppDynamicConversationOnline) error
CreateInBatches(values []*model.AppDynamicConversationOnline, batchSize int) error
Save(values ...*model.AppDynamicConversationOnline) error
First() (*model.AppDynamicConversationOnline, error)
Take() (*model.AppDynamicConversationOnline, error)
Last() (*model.AppDynamicConversationOnline, error)
Find() ([]*model.AppDynamicConversationOnline, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppDynamicConversationOnline, err error)
FindInBatches(result *[]*model.AppDynamicConversationOnline, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.AppDynamicConversationOnline) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IAppDynamicConversationOnlineDo
Assign(attrs ...field.AssignExpr) IAppDynamicConversationOnlineDo
Joins(fields ...field.RelationField) IAppDynamicConversationOnlineDo
Preload(fields ...field.RelationField) IAppDynamicConversationOnlineDo
FirstOrInit() (*model.AppDynamicConversationOnline, error)
FirstOrCreate() (*model.AppDynamicConversationOnline, error)
FindByPage(offset int, limit int) (result []*model.AppDynamicConversationOnline, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IAppDynamicConversationOnlineDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (a appDynamicConversationOnlineDo) Debug() IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Debug())
}
func (a appDynamicConversationOnlineDo) WithContext(ctx context.Context) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.WithContext(ctx))
}
func (a appDynamicConversationOnlineDo) ReadDB() IAppDynamicConversationOnlineDo {
return a.Clauses(dbresolver.Read)
}
func (a appDynamicConversationOnlineDo) WriteDB() IAppDynamicConversationOnlineDo {
return a.Clauses(dbresolver.Write)
}
func (a appDynamicConversationOnlineDo) Session(config *gorm.Session) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Session(config))
}
func (a appDynamicConversationOnlineDo) Clauses(conds ...clause.Expression) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Clauses(conds...))
}
func (a appDynamicConversationOnlineDo) Returning(value interface{}, columns ...string) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Returning(value, columns...))
}
func (a appDynamicConversationOnlineDo) Not(conds ...gen.Condition) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Not(conds...))
}
func (a appDynamicConversationOnlineDo) Or(conds ...gen.Condition) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Or(conds...))
}
func (a appDynamicConversationOnlineDo) Select(conds ...field.Expr) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Select(conds...))
}
func (a appDynamicConversationOnlineDo) Where(conds ...gen.Condition) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Where(conds...))
}
func (a appDynamicConversationOnlineDo) Order(conds ...field.Expr) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Order(conds...))
}
func (a appDynamicConversationOnlineDo) Distinct(cols ...field.Expr) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Distinct(cols...))
}
func (a appDynamicConversationOnlineDo) Omit(cols ...field.Expr) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Omit(cols...))
}
func (a appDynamicConversationOnlineDo) Join(table schema.Tabler, on ...field.Expr) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Join(table, on...))
}
func (a appDynamicConversationOnlineDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.LeftJoin(table, on...))
}
func (a appDynamicConversationOnlineDo) RightJoin(table schema.Tabler, on ...field.Expr) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.RightJoin(table, on...))
}
func (a appDynamicConversationOnlineDo) Group(cols ...field.Expr) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Group(cols...))
}
func (a appDynamicConversationOnlineDo) Having(conds ...gen.Condition) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Having(conds...))
}
func (a appDynamicConversationOnlineDo) Limit(limit int) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Limit(limit))
}
func (a appDynamicConversationOnlineDo) Offset(offset int) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Offset(offset))
}
func (a appDynamicConversationOnlineDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Scopes(funcs...))
}
func (a appDynamicConversationOnlineDo) Unscoped() IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Unscoped())
}
func (a appDynamicConversationOnlineDo) Create(values ...*model.AppDynamicConversationOnline) error {
if len(values) == 0 {
return nil
}
return a.DO.Create(values)
}
func (a appDynamicConversationOnlineDo) CreateInBatches(values []*model.AppDynamicConversationOnline, batchSize int) error {
return a.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (a appDynamicConversationOnlineDo) Save(values ...*model.AppDynamicConversationOnline) error {
if len(values) == 0 {
return nil
}
return a.DO.Save(values)
}
func (a appDynamicConversationOnlineDo) First() (*model.AppDynamicConversationOnline, error) {
if result, err := a.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.AppDynamicConversationOnline), nil
}
}
func (a appDynamicConversationOnlineDo) Take() (*model.AppDynamicConversationOnline, error) {
if result, err := a.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.AppDynamicConversationOnline), nil
}
}
func (a appDynamicConversationOnlineDo) Last() (*model.AppDynamicConversationOnline, error) {
if result, err := a.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.AppDynamicConversationOnline), nil
}
}
func (a appDynamicConversationOnlineDo) Find() ([]*model.AppDynamicConversationOnline, error) {
result, err := a.DO.Find()
return result.([]*model.AppDynamicConversationOnline), err
}
func (a appDynamicConversationOnlineDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppDynamicConversationOnline, err error) {
buf := make([]*model.AppDynamicConversationOnline, 0, batchSize)
err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (a appDynamicConversationOnlineDo) FindInBatches(result *[]*model.AppDynamicConversationOnline, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return a.DO.FindInBatches(result, batchSize, fc)
}
func (a appDynamicConversationOnlineDo) Attrs(attrs ...field.AssignExpr) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Attrs(attrs...))
}
func (a appDynamicConversationOnlineDo) Assign(attrs ...field.AssignExpr) IAppDynamicConversationOnlineDo {
return a.withDO(a.DO.Assign(attrs...))
}
func (a appDynamicConversationOnlineDo) Joins(fields ...field.RelationField) IAppDynamicConversationOnlineDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Joins(_f))
}
return &a
}
func (a appDynamicConversationOnlineDo) Preload(fields ...field.RelationField) IAppDynamicConversationOnlineDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Preload(_f))
}
return &a
}
func (a appDynamicConversationOnlineDo) FirstOrInit() (*model.AppDynamicConversationOnline, error) {
if result, err := a.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.AppDynamicConversationOnline), nil
}
}
func (a appDynamicConversationOnlineDo) FirstOrCreate() (*model.AppDynamicConversationOnline, error) {
if result, err := a.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.AppDynamicConversationOnline), nil
}
}
func (a appDynamicConversationOnlineDo) FindByPage(offset int, limit int) (result []*model.AppDynamicConversationOnline, count int64, err error) {
result, err = a.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = a.Offset(-1).Limit(-1).Count()
return
}
func (a appDynamicConversationOnlineDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = a.Count()
if err != nil {
return
}
err = a.Offset(offset).Limit(limit).Scan(result)
return
}
func (a appDynamicConversationOnlineDo) Scan(result interface{}) (err error) {
return a.DO.Scan(result)
}
func (a appDynamicConversationOnlineDo) Delete(models ...*model.AppDynamicConversationOnline) (result gen.ResultInfo, err error) {
return a.DO.Delete(models)
}
func (a *appDynamicConversationOnlineDo) withDO(do gen.Dao) *appDynamicConversationOnlineDo {
a.DO = *do.(*gen.DO)
return a
}

View File

@@ -0,0 +1,404 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo/dal/model"
)
func newAppStaticConversationDraft(db *gorm.DB, opts ...gen.DOOption) appStaticConversationDraft {
_appStaticConversationDraft := appStaticConversationDraft{}
_appStaticConversationDraft.appStaticConversationDraftDo.UseDB(db, opts...)
_appStaticConversationDraft.appStaticConversationDraftDo.UseModel(&model.AppStaticConversationDraft{})
tableName := _appStaticConversationDraft.appStaticConversationDraftDo.TableName()
_appStaticConversationDraft.ALL = field.NewAsterisk(tableName)
_appStaticConversationDraft.ID = field.NewInt64(tableName, "id")
_appStaticConversationDraft.TemplateID = field.NewInt64(tableName, "template_id")
_appStaticConversationDraft.UserID = field.NewInt64(tableName, "user_id")
_appStaticConversationDraft.ConnectorID = field.NewInt64(tableName, "connector_id")
_appStaticConversationDraft.ConversationID = field.NewInt64(tableName, "conversation_id")
_appStaticConversationDraft.CreatedAt = field.NewInt64(tableName, "created_at")
_appStaticConversationDraft.DeletedAt = field.NewField(tableName, "deleted_at")
_appStaticConversationDraft.fillFieldMap()
return _appStaticConversationDraft
}
type appStaticConversationDraft struct {
appStaticConversationDraftDo
ALL field.Asterisk
ID field.Int64 // id
TemplateID field.Int64 // template id
UserID field.Int64 // user id
ConnectorID field.Int64 // connector id
ConversationID field.Int64 // conversation id
CreatedAt field.Int64 // create time in millisecond
DeletedAt field.Field // delete time in millisecond
fieldMap map[string]field.Expr
}
func (a appStaticConversationDraft) Table(newTableName string) *appStaticConversationDraft {
a.appStaticConversationDraftDo.UseTable(newTableName)
return a.updateTableName(newTableName)
}
func (a appStaticConversationDraft) As(alias string) *appStaticConversationDraft {
a.appStaticConversationDraftDo.DO = *(a.appStaticConversationDraftDo.As(alias).(*gen.DO))
return a.updateTableName(alias)
}
func (a *appStaticConversationDraft) updateTableName(table string) *appStaticConversationDraft {
a.ALL = field.NewAsterisk(table)
a.ID = field.NewInt64(table, "id")
a.TemplateID = field.NewInt64(table, "template_id")
a.UserID = field.NewInt64(table, "user_id")
a.ConnectorID = field.NewInt64(table, "connector_id")
a.ConversationID = field.NewInt64(table, "conversation_id")
a.CreatedAt = field.NewInt64(table, "created_at")
a.DeletedAt = field.NewField(table, "deleted_at")
a.fillFieldMap()
return a
}
func (a *appStaticConversationDraft) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := a.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (a *appStaticConversationDraft) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 7)
a.fieldMap["id"] = a.ID
a.fieldMap["template_id"] = a.TemplateID
a.fieldMap["user_id"] = a.UserID
a.fieldMap["connector_id"] = a.ConnectorID
a.fieldMap["conversation_id"] = a.ConversationID
a.fieldMap["created_at"] = a.CreatedAt
a.fieldMap["deleted_at"] = a.DeletedAt
}
func (a appStaticConversationDraft) clone(db *gorm.DB) appStaticConversationDraft {
a.appStaticConversationDraftDo.ReplaceConnPool(db.Statement.ConnPool)
return a
}
func (a appStaticConversationDraft) replaceDB(db *gorm.DB) appStaticConversationDraft {
a.appStaticConversationDraftDo.ReplaceDB(db)
return a
}
type appStaticConversationDraftDo struct{ gen.DO }
type IAppStaticConversationDraftDo interface {
gen.SubQuery
Debug() IAppStaticConversationDraftDo
WithContext(ctx context.Context) IAppStaticConversationDraftDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IAppStaticConversationDraftDo
WriteDB() IAppStaticConversationDraftDo
As(alias string) gen.Dao
Session(config *gorm.Session) IAppStaticConversationDraftDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IAppStaticConversationDraftDo
Not(conds ...gen.Condition) IAppStaticConversationDraftDo
Or(conds ...gen.Condition) IAppStaticConversationDraftDo
Select(conds ...field.Expr) IAppStaticConversationDraftDo
Where(conds ...gen.Condition) IAppStaticConversationDraftDo
Order(conds ...field.Expr) IAppStaticConversationDraftDo
Distinct(cols ...field.Expr) IAppStaticConversationDraftDo
Omit(cols ...field.Expr) IAppStaticConversationDraftDo
Join(table schema.Tabler, on ...field.Expr) IAppStaticConversationDraftDo
LeftJoin(table schema.Tabler, on ...field.Expr) IAppStaticConversationDraftDo
RightJoin(table schema.Tabler, on ...field.Expr) IAppStaticConversationDraftDo
Group(cols ...field.Expr) IAppStaticConversationDraftDo
Having(conds ...gen.Condition) IAppStaticConversationDraftDo
Limit(limit int) IAppStaticConversationDraftDo
Offset(offset int) IAppStaticConversationDraftDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IAppStaticConversationDraftDo
Unscoped() IAppStaticConversationDraftDo
Create(values ...*model.AppStaticConversationDraft) error
CreateInBatches(values []*model.AppStaticConversationDraft, batchSize int) error
Save(values ...*model.AppStaticConversationDraft) error
First() (*model.AppStaticConversationDraft, error)
Take() (*model.AppStaticConversationDraft, error)
Last() (*model.AppStaticConversationDraft, error)
Find() ([]*model.AppStaticConversationDraft, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppStaticConversationDraft, err error)
FindInBatches(result *[]*model.AppStaticConversationDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.AppStaticConversationDraft) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IAppStaticConversationDraftDo
Assign(attrs ...field.AssignExpr) IAppStaticConversationDraftDo
Joins(fields ...field.RelationField) IAppStaticConversationDraftDo
Preload(fields ...field.RelationField) IAppStaticConversationDraftDo
FirstOrInit() (*model.AppStaticConversationDraft, error)
FirstOrCreate() (*model.AppStaticConversationDraft, error)
FindByPage(offset int, limit int) (result []*model.AppStaticConversationDraft, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IAppStaticConversationDraftDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (a appStaticConversationDraftDo) Debug() IAppStaticConversationDraftDo {
return a.withDO(a.DO.Debug())
}
func (a appStaticConversationDraftDo) WithContext(ctx context.Context) IAppStaticConversationDraftDo {
return a.withDO(a.DO.WithContext(ctx))
}
func (a appStaticConversationDraftDo) ReadDB() IAppStaticConversationDraftDo {
return a.Clauses(dbresolver.Read)
}
func (a appStaticConversationDraftDo) WriteDB() IAppStaticConversationDraftDo {
return a.Clauses(dbresolver.Write)
}
func (a appStaticConversationDraftDo) Session(config *gorm.Session) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Session(config))
}
func (a appStaticConversationDraftDo) Clauses(conds ...clause.Expression) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Clauses(conds...))
}
func (a appStaticConversationDraftDo) Returning(value interface{}, columns ...string) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Returning(value, columns...))
}
func (a appStaticConversationDraftDo) Not(conds ...gen.Condition) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Not(conds...))
}
func (a appStaticConversationDraftDo) Or(conds ...gen.Condition) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Or(conds...))
}
func (a appStaticConversationDraftDo) Select(conds ...field.Expr) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Select(conds...))
}
func (a appStaticConversationDraftDo) Where(conds ...gen.Condition) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Where(conds...))
}
func (a appStaticConversationDraftDo) Order(conds ...field.Expr) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Order(conds...))
}
func (a appStaticConversationDraftDo) Distinct(cols ...field.Expr) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Distinct(cols...))
}
func (a appStaticConversationDraftDo) Omit(cols ...field.Expr) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Omit(cols...))
}
func (a appStaticConversationDraftDo) Join(table schema.Tabler, on ...field.Expr) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Join(table, on...))
}
func (a appStaticConversationDraftDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAppStaticConversationDraftDo {
return a.withDO(a.DO.LeftJoin(table, on...))
}
func (a appStaticConversationDraftDo) RightJoin(table schema.Tabler, on ...field.Expr) IAppStaticConversationDraftDo {
return a.withDO(a.DO.RightJoin(table, on...))
}
func (a appStaticConversationDraftDo) Group(cols ...field.Expr) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Group(cols...))
}
func (a appStaticConversationDraftDo) Having(conds ...gen.Condition) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Having(conds...))
}
func (a appStaticConversationDraftDo) Limit(limit int) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Limit(limit))
}
func (a appStaticConversationDraftDo) Offset(offset int) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Offset(offset))
}
func (a appStaticConversationDraftDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Scopes(funcs...))
}
func (a appStaticConversationDraftDo) Unscoped() IAppStaticConversationDraftDo {
return a.withDO(a.DO.Unscoped())
}
func (a appStaticConversationDraftDo) Create(values ...*model.AppStaticConversationDraft) error {
if len(values) == 0 {
return nil
}
return a.DO.Create(values)
}
func (a appStaticConversationDraftDo) CreateInBatches(values []*model.AppStaticConversationDraft, batchSize int) error {
return a.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (a appStaticConversationDraftDo) Save(values ...*model.AppStaticConversationDraft) error {
if len(values) == 0 {
return nil
}
return a.DO.Save(values)
}
func (a appStaticConversationDraftDo) First() (*model.AppStaticConversationDraft, error) {
if result, err := a.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.AppStaticConversationDraft), nil
}
}
func (a appStaticConversationDraftDo) Take() (*model.AppStaticConversationDraft, error) {
if result, err := a.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.AppStaticConversationDraft), nil
}
}
func (a appStaticConversationDraftDo) Last() (*model.AppStaticConversationDraft, error) {
if result, err := a.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.AppStaticConversationDraft), nil
}
}
func (a appStaticConversationDraftDo) Find() ([]*model.AppStaticConversationDraft, error) {
result, err := a.DO.Find()
return result.([]*model.AppStaticConversationDraft), err
}
func (a appStaticConversationDraftDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppStaticConversationDraft, err error) {
buf := make([]*model.AppStaticConversationDraft, 0, batchSize)
err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (a appStaticConversationDraftDo) FindInBatches(result *[]*model.AppStaticConversationDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return a.DO.FindInBatches(result, batchSize, fc)
}
func (a appStaticConversationDraftDo) Attrs(attrs ...field.AssignExpr) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Attrs(attrs...))
}
func (a appStaticConversationDraftDo) Assign(attrs ...field.AssignExpr) IAppStaticConversationDraftDo {
return a.withDO(a.DO.Assign(attrs...))
}
func (a appStaticConversationDraftDo) Joins(fields ...field.RelationField) IAppStaticConversationDraftDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Joins(_f))
}
return &a
}
func (a appStaticConversationDraftDo) Preload(fields ...field.RelationField) IAppStaticConversationDraftDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Preload(_f))
}
return &a
}
func (a appStaticConversationDraftDo) FirstOrInit() (*model.AppStaticConversationDraft, error) {
if result, err := a.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.AppStaticConversationDraft), nil
}
}
func (a appStaticConversationDraftDo) FirstOrCreate() (*model.AppStaticConversationDraft, error) {
if result, err := a.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.AppStaticConversationDraft), nil
}
}
func (a appStaticConversationDraftDo) FindByPage(offset int, limit int) (result []*model.AppStaticConversationDraft, count int64, err error) {
result, err = a.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = a.Offset(-1).Limit(-1).Count()
return
}
func (a appStaticConversationDraftDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = a.Count()
if err != nil {
return
}
err = a.Offset(offset).Limit(limit).Scan(result)
return
}
func (a appStaticConversationDraftDo) Scan(result interface{}) (err error) {
return a.DO.Scan(result)
}
func (a appStaticConversationDraftDo) Delete(models ...*model.AppStaticConversationDraft) (result gen.ResultInfo, err error) {
return a.DO.Delete(models)
}
func (a *appStaticConversationDraftDo) withDO(do gen.Dao) *appStaticConversationDraftDo {
a.DO = *do.(*gen.DO)
return a
}

View File

@@ -0,0 +1,400 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo/dal/model"
)
func newAppStaticConversationOnline(db *gorm.DB, opts ...gen.DOOption) appStaticConversationOnline {
_appStaticConversationOnline := appStaticConversationOnline{}
_appStaticConversationOnline.appStaticConversationOnlineDo.UseDB(db, opts...)
_appStaticConversationOnline.appStaticConversationOnlineDo.UseModel(&model.AppStaticConversationOnline{})
tableName := _appStaticConversationOnline.appStaticConversationOnlineDo.TableName()
_appStaticConversationOnline.ALL = field.NewAsterisk(tableName)
_appStaticConversationOnline.ID = field.NewInt64(tableName, "id")
_appStaticConversationOnline.TemplateID = field.NewInt64(tableName, "template_id")
_appStaticConversationOnline.UserID = field.NewInt64(tableName, "user_id")
_appStaticConversationOnline.ConnectorID = field.NewInt64(tableName, "connector_id")
_appStaticConversationOnline.ConversationID = field.NewInt64(tableName, "conversation_id")
_appStaticConversationOnline.CreatedAt = field.NewInt64(tableName, "created_at")
_appStaticConversationOnline.fillFieldMap()
return _appStaticConversationOnline
}
type appStaticConversationOnline struct {
appStaticConversationOnlineDo
ALL field.Asterisk
ID field.Int64 // id
TemplateID field.Int64 // template id
UserID field.Int64 // user id
ConnectorID field.Int64 // connector id
ConversationID field.Int64 // conversation id
CreatedAt field.Int64 // create time in millisecond
fieldMap map[string]field.Expr
}
func (a appStaticConversationOnline) Table(newTableName string) *appStaticConversationOnline {
a.appStaticConversationOnlineDo.UseTable(newTableName)
return a.updateTableName(newTableName)
}
func (a appStaticConversationOnline) As(alias string) *appStaticConversationOnline {
a.appStaticConversationOnlineDo.DO = *(a.appStaticConversationOnlineDo.As(alias).(*gen.DO))
return a.updateTableName(alias)
}
func (a *appStaticConversationOnline) updateTableName(table string) *appStaticConversationOnline {
a.ALL = field.NewAsterisk(table)
a.ID = field.NewInt64(table, "id")
a.TemplateID = field.NewInt64(table, "template_id")
a.UserID = field.NewInt64(table, "user_id")
a.ConnectorID = field.NewInt64(table, "connector_id")
a.ConversationID = field.NewInt64(table, "conversation_id")
a.CreatedAt = field.NewInt64(table, "created_at")
a.fillFieldMap()
return a
}
func (a *appStaticConversationOnline) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := a.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (a *appStaticConversationOnline) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 6)
a.fieldMap["id"] = a.ID
a.fieldMap["template_id"] = a.TemplateID
a.fieldMap["user_id"] = a.UserID
a.fieldMap["connector_id"] = a.ConnectorID
a.fieldMap["conversation_id"] = a.ConversationID
a.fieldMap["created_at"] = a.CreatedAt
}
func (a appStaticConversationOnline) clone(db *gorm.DB) appStaticConversationOnline {
a.appStaticConversationOnlineDo.ReplaceConnPool(db.Statement.ConnPool)
return a
}
func (a appStaticConversationOnline) replaceDB(db *gorm.DB) appStaticConversationOnline {
a.appStaticConversationOnlineDo.ReplaceDB(db)
return a
}
type appStaticConversationOnlineDo struct{ gen.DO }
type IAppStaticConversationOnlineDo interface {
gen.SubQuery
Debug() IAppStaticConversationOnlineDo
WithContext(ctx context.Context) IAppStaticConversationOnlineDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IAppStaticConversationOnlineDo
WriteDB() IAppStaticConversationOnlineDo
As(alias string) gen.Dao
Session(config *gorm.Session) IAppStaticConversationOnlineDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IAppStaticConversationOnlineDo
Not(conds ...gen.Condition) IAppStaticConversationOnlineDo
Or(conds ...gen.Condition) IAppStaticConversationOnlineDo
Select(conds ...field.Expr) IAppStaticConversationOnlineDo
Where(conds ...gen.Condition) IAppStaticConversationOnlineDo
Order(conds ...field.Expr) IAppStaticConversationOnlineDo
Distinct(cols ...field.Expr) IAppStaticConversationOnlineDo
Omit(cols ...field.Expr) IAppStaticConversationOnlineDo
Join(table schema.Tabler, on ...field.Expr) IAppStaticConversationOnlineDo
LeftJoin(table schema.Tabler, on ...field.Expr) IAppStaticConversationOnlineDo
RightJoin(table schema.Tabler, on ...field.Expr) IAppStaticConversationOnlineDo
Group(cols ...field.Expr) IAppStaticConversationOnlineDo
Having(conds ...gen.Condition) IAppStaticConversationOnlineDo
Limit(limit int) IAppStaticConversationOnlineDo
Offset(offset int) IAppStaticConversationOnlineDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IAppStaticConversationOnlineDo
Unscoped() IAppStaticConversationOnlineDo
Create(values ...*model.AppStaticConversationOnline) error
CreateInBatches(values []*model.AppStaticConversationOnline, batchSize int) error
Save(values ...*model.AppStaticConversationOnline) error
First() (*model.AppStaticConversationOnline, error)
Take() (*model.AppStaticConversationOnline, error)
Last() (*model.AppStaticConversationOnline, error)
Find() ([]*model.AppStaticConversationOnline, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppStaticConversationOnline, err error)
FindInBatches(result *[]*model.AppStaticConversationOnline, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.AppStaticConversationOnline) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IAppStaticConversationOnlineDo
Assign(attrs ...field.AssignExpr) IAppStaticConversationOnlineDo
Joins(fields ...field.RelationField) IAppStaticConversationOnlineDo
Preload(fields ...field.RelationField) IAppStaticConversationOnlineDo
FirstOrInit() (*model.AppStaticConversationOnline, error)
FirstOrCreate() (*model.AppStaticConversationOnline, error)
FindByPage(offset int, limit int) (result []*model.AppStaticConversationOnline, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IAppStaticConversationOnlineDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (a appStaticConversationOnlineDo) Debug() IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Debug())
}
func (a appStaticConversationOnlineDo) WithContext(ctx context.Context) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.WithContext(ctx))
}
func (a appStaticConversationOnlineDo) ReadDB() IAppStaticConversationOnlineDo {
return a.Clauses(dbresolver.Read)
}
func (a appStaticConversationOnlineDo) WriteDB() IAppStaticConversationOnlineDo {
return a.Clauses(dbresolver.Write)
}
func (a appStaticConversationOnlineDo) Session(config *gorm.Session) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Session(config))
}
func (a appStaticConversationOnlineDo) Clauses(conds ...clause.Expression) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Clauses(conds...))
}
func (a appStaticConversationOnlineDo) Returning(value interface{}, columns ...string) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Returning(value, columns...))
}
func (a appStaticConversationOnlineDo) Not(conds ...gen.Condition) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Not(conds...))
}
func (a appStaticConversationOnlineDo) Or(conds ...gen.Condition) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Or(conds...))
}
func (a appStaticConversationOnlineDo) Select(conds ...field.Expr) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Select(conds...))
}
func (a appStaticConversationOnlineDo) Where(conds ...gen.Condition) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Where(conds...))
}
func (a appStaticConversationOnlineDo) Order(conds ...field.Expr) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Order(conds...))
}
func (a appStaticConversationOnlineDo) Distinct(cols ...field.Expr) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Distinct(cols...))
}
func (a appStaticConversationOnlineDo) Omit(cols ...field.Expr) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Omit(cols...))
}
func (a appStaticConversationOnlineDo) Join(table schema.Tabler, on ...field.Expr) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Join(table, on...))
}
func (a appStaticConversationOnlineDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.LeftJoin(table, on...))
}
func (a appStaticConversationOnlineDo) RightJoin(table schema.Tabler, on ...field.Expr) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.RightJoin(table, on...))
}
func (a appStaticConversationOnlineDo) Group(cols ...field.Expr) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Group(cols...))
}
func (a appStaticConversationOnlineDo) Having(conds ...gen.Condition) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Having(conds...))
}
func (a appStaticConversationOnlineDo) Limit(limit int) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Limit(limit))
}
func (a appStaticConversationOnlineDo) Offset(offset int) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Offset(offset))
}
func (a appStaticConversationOnlineDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Scopes(funcs...))
}
func (a appStaticConversationOnlineDo) Unscoped() IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Unscoped())
}
func (a appStaticConversationOnlineDo) Create(values ...*model.AppStaticConversationOnline) error {
if len(values) == 0 {
return nil
}
return a.DO.Create(values)
}
func (a appStaticConversationOnlineDo) CreateInBatches(values []*model.AppStaticConversationOnline, batchSize int) error {
return a.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (a appStaticConversationOnlineDo) Save(values ...*model.AppStaticConversationOnline) error {
if len(values) == 0 {
return nil
}
return a.DO.Save(values)
}
func (a appStaticConversationOnlineDo) First() (*model.AppStaticConversationOnline, error) {
if result, err := a.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.AppStaticConversationOnline), nil
}
}
func (a appStaticConversationOnlineDo) Take() (*model.AppStaticConversationOnline, error) {
if result, err := a.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.AppStaticConversationOnline), nil
}
}
func (a appStaticConversationOnlineDo) Last() (*model.AppStaticConversationOnline, error) {
if result, err := a.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.AppStaticConversationOnline), nil
}
}
func (a appStaticConversationOnlineDo) Find() ([]*model.AppStaticConversationOnline, error) {
result, err := a.DO.Find()
return result.([]*model.AppStaticConversationOnline), err
}
func (a appStaticConversationOnlineDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppStaticConversationOnline, err error) {
buf := make([]*model.AppStaticConversationOnline, 0, batchSize)
err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (a appStaticConversationOnlineDo) FindInBatches(result *[]*model.AppStaticConversationOnline, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return a.DO.FindInBatches(result, batchSize, fc)
}
func (a appStaticConversationOnlineDo) Attrs(attrs ...field.AssignExpr) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Attrs(attrs...))
}
func (a appStaticConversationOnlineDo) Assign(attrs ...field.AssignExpr) IAppStaticConversationOnlineDo {
return a.withDO(a.DO.Assign(attrs...))
}
func (a appStaticConversationOnlineDo) Joins(fields ...field.RelationField) IAppStaticConversationOnlineDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Joins(_f))
}
return &a
}
func (a appStaticConversationOnlineDo) Preload(fields ...field.RelationField) IAppStaticConversationOnlineDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Preload(_f))
}
return &a
}
func (a appStaticConversationOnlineDo) FirstOrInit() (*model.AppStaticConversationOnline, error) {
if result, err := a.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.AppStaticConversationOnline), nil
}
}
func (a appStaticConversationOnlineDo) FirstOrCreate() (*model.AppStaticConversationOnline, error) {
if result, err := a.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.AppStaticConversationOnline), nil
}
}
func (a appStaticConversationOnlineDo) FindByPage(offset int, limit int) (result []*model.AppStaticConversationOnline, count int64, err error) {
result, err = a.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = a.Offset(-1).Limit(-1).Count()
return
}
func (a appStaticConversationOnlineDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = a.Count()
if err != nil {
return
}
err = a.Offset(offset).Limit(limit).Scan(result)
return
}
func (a appStaticConversationOnlineDo) Scan(result interface{}) (err error) {
return a.DO.Scan(result)
}
func (a appStaticConversationOnlineDo) Delete(models ...*model.AppStaticConversationOnline) (result gen.ResultInfo, err error) {
return a.DO.Delete(models)
}
func (a *appStaticConversationOnlineDo) withDO(do gen.Dao) *appStaticConversationOnlineDo {
a.DO = *do.(*gen.DO)
return a
}

View File

@@ -0,0 +1,440 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo/dal/model"
)
func newChatFlowRoleConfig(db *gorm.DB, opts ...gen.DOOption) chatFlowRoleConfig {
_chatFlowRoleConfig := chatFlowRoleConfig{}
_chatFlowRoleConfig.chatFlowRoleConfigDo.UseDB(db, opts...)
_chatFlowRoleConfig.chatFlowRoleConfigDo.UseModel(&model.ChatFlowRoleConfig{})
tableName := _chatFlowRoleConfig.chatFlowRoleConfigDo.TableName()
_chatFlowRoleConfig.ALL = field.NewAsterisk(tableName)
_chatFlowRoleConfig.ID = field.NewInt64(tableName, "id")
_chatFlowRoleConfig.WorkflowID = field.NewInt64(tableName, "workflow_id")
_chatFlowRoleConfig.Name = field.NewString(tableName, "name")
_chatFlowRoleConfig.Description = field.NewString(tableName, "description")
_chatFlowRoleConfig.Version = field.NewString(tableName, "version")
_chatFlowRoleConfig.Avatar = field.NewString(tableName, "avatar")
_chatFlowRoleConfig.BackgroundImageInfo = field.NewString(tableName, "background_image_info")
_chatFlowRoleConfig.OnboardingInfo = field.NewString(tableName, "onboarding_info")
_chatFlowRoleConfig.SuggestReplyInfo = field.NewString(tableName, "suggest_reply_info")
_chatFlowRoleConfig.AudioConfig = field.NewString(tableName, "audio_config")
_chatFlowRoleConfig.UserInputConfig = field.NewString(tableName, "user_input_config")
_chatFlowRoleConfig.CreatorID = field.NewInt64(tableName, "creator_id")
_chatFlowRoleConfig.CreatedAt = field.NewInt64(tableName, "created_at")
_chatFlowRoleConfig.UpdatedAt = field.NewInt64(tableName, "updated_at")
_chatFlowRoleConfig.DeletedAt = field.NewField(tableName, "deleted_at")
_chatFlowRoleConfig.ConnectorID = field.NewInt64(tableName, "connector_id")
_chatFlowRoleConfig.fillFieldMap()
return _chatFlowRoleConfig
}
type chatFlowRoleConfig struct {
chatFlowRoleConfigDo
ALL field.Asterisk
ID field.Int64 // id
WorkflowID field.Int64 // workflow id
Name field.String // role name
Description field.String // role description
Version field.String // version
Avatar field.String // avatar uri
BackgroundImageInfo field.String // background image information, object structure
OnboardingInfo field.String // intro information, object structure
SuggestReplyInfo field.String // user suggestions, object structure
AudioConfig field.String // agent audio config, object structure
UserInputConfig field.String // user input config, object structure
CreatorID field.Int64 // creator id
CreatedAt field.Int64 // create time in millisecond
UpdatedAt field.Int64 // update time in millisecond
DeletedAt field.Field // delete time in millisecond
ConnectorID field.Int64 // connector id
fieldMap map[string]field.Expr
}
func (c chatFlowRoleConfig) Table(newTableName string) *chatFlowRoleConfig {
c.chatFlowRoleConfigDo.UseTable(newTableName)
return c.updateTableName(newTableName)
}
func (c chatFlowRoleConfig) As(alias string) *chatFlowRoleConfig {
c.chatFlowRoleConfigDo.DO = *(c.chatFlowRoleConfigDo.As(alias).(*gen.DO))
return c.updateTableName(alias)
}
func (c *chatFlowRoleConfig) updateTableName(table string) *chatFlowRoleConfig {
c.ALL = field.NewAsterisk(table)
c.ID = field.NewInt64(table, "id")
c.WorkflowID = field.NewInt64(table, "workflow_id")
c.Name = field.NewString(table, "name")
c.Description = field.NewString(table, "description")
c.Version = field.NewString(table, "version")
c.Avatar = field.NewString(table, "avatar")
c.BackgroundImageInfo = field.NewString(table, "background_image_info")
c.OnboardingInfo = field.NewString(table, "onboarding_info")
c.SuggestReplyInfo = field.NewString(table, "suggest_reply_info")
c.AudioConfig = field.NewString(table, "audio_config")
c.UserInputConfig = field.NewString(table, "user_input_config")
c.CreatorID = field.NewInt64(table, "creator_id")
c.CreatedAt = field.NewInt64(table, "created_at")
c.UpdatedAt = field.NewInt64(table, "updated_at")
c.DeletedAt = field.NewField(table, "deleted_at")
c.ConnectorID = field.NewInt64(table, "connector_id")
c.fillFieldMap()
return c
}
func (c *chatFlowRoleConfig) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := c.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (c *chatFlowRoleConfig) fillFieldMap() {
c.fieldMap = make(map[string]field.Expr, 16)
c.fieldMap["id"] = c.ID
c.fieldMap["workflow_id"] = c.WorkflowID
c.fieldMap["name"] = c.Name
c.fieldMap["description"] = c.Description
c.fieldMap["version"] = c.Version
c.fieldMap["avatar"] = c.Avatar
c.fieldMap["background_image_info"] = c.BackgroundImageInfo
c.fieldMap["onboarding_info"] = c.OnboardingInfo
c.fieldMap["suggest_reply_info"] = c.SuggestReplyInfo
c.fieldMap["audio_config"] = c.AudioConfig
c.fieldMap["user_input_config"] = c.UserInputConfig
c.fieldMap["creator_id"] = c.CreatorID
c.fieldMap["created_at"] = c.CreatedAt
c.fieldMap["updated_at"] = c.UpdatedAt
c.fieldMap["deleted_at"] = c.DeletedAt
c.fieldMap["connector_id"] = c.ConnectorID
}
func (c chatFlowRoleConfig) clone(db *gorm.DB) chatFlowRoleConfig {
c.chatFlowRoleConfigDo.ReplaceConnPool(db.Statement.ConnPool)
return c
}
func (c chatFlowRoleConfig) replaceDB(db *gorm.DB) chatFlowRoleConfig {
c.chatFlowRoleConfigDo.ReplaceDB(db)
return c
}
type chatFlowRoleConfigDo struct{ gen.DO }
type IChatFlowRoleConfigDo interface {
gen.SubQuery
Debug() IChatFlowRoleConfigDo
WithContext(ctx context.Context) IChatFlowRoleConfigDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IChatFlowRoleConfigDo
WriteDB() IChatFlowRoleConfigDo
As(alias string) gen.Dao
Session(config *gorm.Session) IChatFlowRoleConfigDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IChatFlowRoleConfigDo
Not(conds ...gen.Condition) IChatFlowRoleConfigDo
Or(conds ...gen.Condition) IChatFlowRoleConfigDo
Select(conds ...field.Expr) IChatFlowRoleConfigDo
Where(conds ...gen.Condition) IChatFlowRoleConfigDo
Order(conds ...field.Expr) IChatFlowRoleConfigDo
Distinct(cols ...field.Expr) IChatFlowRoleConfigDo
Omit(cols ...field.Expr) IChatFlowRoleConfigDo
Join(table schema.Tabler, on ...field.Expr) IChatFlowRoleConfigDo
LeftJoin(table schema.Tabler, on ...field.Expr) IChatFlowRoleConfigDo
RightJoin(table schema.Tabler, on ...field.Expr) IChatFlowRoleConfigDo
Group(cols ...field.Expr) IChatFlowRoleConfigDo
Having(conds ...gen.Condition) IChatFlowRoleConfigDo
Limit(limit int) IChatFlowRoleConfigDo
Offset(offset int) IChatFlowRoleConfigDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IChatFlowRoleConfigDo
Unscoped() IChatFlowRoleConfigDo
Create(values ...*model.ChatFlowRoleConfig) error
CreateInBatches(values []*model.ChatFlowRoleConfig, batchSize int) error
Save(values ...*model.ChatFlowRoleConfig) error
First() (*model.ChatFlowRoleConfig, error)
Take() (*model.ChatFlowRoleConfig, error)
Last() (*model.ChatFlowRoleConfig, error)
Find() ([]*model.ChatFlowRoleConfig, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ChatFlowRoleConfig, err error)
FindInBatches(result *[]*model.ChatFlowRoleConfig, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.ChatFlowRoleConfig) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IChatFlowRoleConfigDo
Assign(attrs ...field.AssignExpr) IChatFlowRoleConfigDo
Joins(fields ...field.RelationField) IChatFlowRoleConfigDo
Preload(fields ...field.RelationField) IChatFlowRoleConfigDo
FirstOrInit() (*model.ChatFlowRoleConfig, error)
FirstOrCreate() (*model.ChatFlowRoleConfig, error)
FindByPage(offset int, limit int) (result []*model.ChatFlowRoleConfig, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IChatFlowRoleConfigDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (c chatFlowRoleConfigDo) Debug() IChatFlowRoleConfigDo {
return c.withDO(c.DO.Debug())
}
func (c chatFlowRoleConfigDo) WithContext(ctx context.Context) IChatFlowRoleConfigDo {
return c.withDO(c.DO.WithContext(ctx))
}
func (c chatFlowRoleConfigDo) ReadDB() IChatFlowRoleConfigDo {
return c.Clauses(dbresolver.Read)
}
func (c chatFlowRoleConfigDo) WriteDB() IChatFlowRoleConfigDo {
return c.Clauses(dbresolver.Write)
}
func (c chatFlowRoleConfigDo) Session(config *gorm.Session) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Session(config))
}
func (c chatFlowRoleConfigDo) Clauses(conds ...clause.Expression) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Clauses(conds...))
}
func (c chatFlowRoleConfigDo) Returning(value interface{}, columns ...string) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Returning(value, columns...))
}
func (c chatFlowRoleConfigDo) Not(conds ...gen.Condition) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Not(conds...))
}
func (c chatFlowRoleConfigDo) Or(conds ...gen.Condition) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Or(conds...))
}
func (c chatFlowRoleConfigDo) Select(conds ...field.Expr) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Select(conds...))
}
func (c chatFlowRoleConfigDo) Where(conds ...gen.Condition) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Where(conds...))
}
func (c chatFlowRoleConfigDo) Order(conds ...field.Expr) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Order(conds...))
}
func (c chatFlowRoleConfigDo) Distinct(cols ...field.Expr) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Distinct(cols...))
}
func (c chatFlowRoleConfigDo) Omit(cols ...field.Expr) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Omit(cols...))
}
func (c chatFlowRoleConfigDo) Join(table schema.Tabler, on ...field.Expr) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Join(table, on...))
}
func (c chatFlowRoleConfigDo) LeftJoin(table schema.Tabler, on ...field.Expr) IChatFlowRoleConfigDo {
return c.withDO(c.DO.LeftJoin(table, on...))
}
func (c chatFlowRoleConfigDo) RightJoin(table schema.Tabler, on ...field.Expr) IChatFlowRoleConfigDo {
return c.withDO(c.DO.RightJoin(table, on...))
}
func (c chatFlowRoleConfigDo) Group(cols ...field.Expr) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Group(cols...))
}
func (c chatFlowRoleConfigDo) Having(conds ...gen.Condition) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Having(conds...))
}
func (c chatFlowRoleConfigDo) Limit(limit int) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Limit(limit))
}
func (c chatFlowRoleConfigDo) Offset(offset int) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Offset(offset))
}
func (c chatFlowRoleConfigDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Scopes(funcs...))
}
func (c chatFlowRoleConfigDo) Unscoped() IChatFlowRoleConfigDo {
return c.withDO(c.DO.Unscoped())
}
func (c chatFlowRoleConfigDo) Create(values ...*model.ChatFlowRoleConfig) error {
if len(values) == 0 {
return nil
}
return c.DO.Create(values)
}
func (c chatFlowRoleConfigDo) CreateInBatches(values []*model.ChatFlowRoleConfig, batchSize int) error {
return c.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (c chatFlowRoleConfigDo) Save(values ...*model.ChatFlowRoleConfig) error {
if len(values) == 0 {
return nil
}
return c.DO.Save(values)
}
func (c chatFlowRoleConfigDo) First() (*model.ChatFlowRoleConfig, error) {
if result, err := c.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.ChatFlowRoleConfig), nil
}
}
func (c chatFlowRoleConfigDo) Take() (*model.ChatFlowRoleConfig, error) {
if result, err := c.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.ChatFlowRoleConfig), nil
}
}
func (c chatFlowRoleConfigDo) Last() (*model.ChatFlowRoleConfig, error) {
if result, err := c.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.ChatFlowRoleConfig), nil
}
}
func (c chatFlowRoleConfigDo) Find() ([]*model.ChatFlowRoleConfig, error) {
result, err := c.DO.Find()
return result.([]*model.ChatFlowRoleConfig), err
}
func (c chatFlowRoleConfigDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ChatFlowRoleConfig, err error) {
buf := make([]*model.ChatFlowRoleConfig, 0, batchSize)
err = c.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (c chatFlowRoleConfigDo) FindInBatches(result *[]*model.ChatFlowRoleConfig, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return c.DO.FindInBatches(result, batchSize, fc)
}
func (c chatFlowRoleConfigDo) Attrs(attrs ...field.AssignExpr) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Attrs(attrs...))
}
func (c chatFlowRoleConfigDo) Assign(attrs ...field.AssignExpr) IChatFlowRoleConfigDo {
return c.withDO(c.DO.Assign(attrs...))
}
func (c chatFlowRoleConfigDo) Joins(fields ...field.RelationField) IChatFlowRoleConfigDo {
for _, _f := range fields {
c = *c.withDO(c.DO.Joins(_f))
}
return &c
}
func (c chatFlowRoleConfigDo) Preload(fields ...field.RelationField) IChatFlowRoleConfigDo {
for _, _f := range fields {
c = *c.withDO(c.DO.Preload(_f))
}
return &c
}
func (c chatFlowRoleConfigDo) FirstOrInit() (*model.ChatFlowRoleConfig, error) {
if result, err := c.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.ChatFlowRoleConfig), nil
}
}
func (c chatFlowRoleConfigDo) FirstOrCreate() (*model.ChatFlowRoleConfig, error) {
if result, err := c.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.ChatFlowRoleConfig), nil
}
}
func (c chatFlowRoleConfigDo) FindByPage(offset int, limit int) (result []*model.ChatFlowRoleConfig, count int64, err error) {
result, err = c.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = c.Offset(-1).Limit(-1).Count()
return
}
func (c chatFlowRoleConfigDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = c.Count()
if err != nil {
return
}
err = c.Offset(offset).Limit(limit).Scan(result)
return
}
func (c chatFlowRoleConfigDo) Scan(result interface{}) (err error) {
return c.DO.Scan(result)
}
func (c chatFlowRoleConfigDo) Delete(models ...*model.ChatFlowRoleConfig) (result gen.ResultInfo, err error) {
return c.DO.Delete(models)
}
func (c *chatFlowRoleConfigDo) withDO(do gen.Dao) *chatFlowRoleConfigDo {
c.DO = *do.(*gen.DO)
return c
}

View File

@@ -16,20 +16,34 @@ import (
)
var (
Q = new(Query)
ConnectorWorkflowVersion *connectorWorkflowVersion
NodeExecution *nodeExecution
WorkflowDraft *workflowDraft
WorkflowExecution *workflowExecution
WorkflowMeta *workflowMeta
WorkflowReference *workflowReference
WorkflowSnapshot *workflowSnapshot
WorkflowVersion *workflowVersion
Q = new(Query)
ConnectorWorkflowVersion *connectorWorkflowVersion
AppConversationTemplateDraft *appConversationTemplateDraft
AppConversationTemplateOnline *appConversationTemplateOnline
AppDynamicConversationDraft *appDynamicConversationDraft
AppDynamicConversationOnline *appDynamicConversationOnline
AppStaticConversationDraft *appStaticConversationDraft
AppStaticConversationOnline *appStaticConversationOnline
ChatFlowRoleConfig *chatFlowRoleConfig
NodeExecution *nodeExecution
WorkflowDraft *workflowDraft
WorkflowExecution *workflowExecution
WorkflowMeta *workflowMeta
WorkflowReference *workflowReference
WorkflowSnapshot *workflowSnapshot
WorkflowVersion *workflowVersion
)
func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
*Q = *Use(db, opts...)
ConnectorWorkflowVersion = &Q.ConnectorWorkflowVersion
AppConversationTemplateDraft = &Q.AppConversationTemplateDraft
AppConversationTemplateOnline = &Q.AppConversationTemplateOnline
AppDynamicConversationDraft = &Q.AppDynamicConversationDraft
AppDynamicConversationOnline = &Q.AppDynamicConversationOnline
AppStaticConversationDraft = &Q.AppStaticConversationDraft
AppStaticConversationOnline = &Q.AppStaticConversationOnline
ChatFlowRoleConfig = &Q.ChatFlowRoleConfig
NodeExecution = &Q.NodeExecution
WorkflowDraft = &Q.WorkflowDraft
WorkflowExecution = &Q.WorkflowExecution
@@ -41,44 +55,65 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
return &Query{
db: db,
ConnectorWorkflowVersion: newConnectorWorkflowVersion(db, opts...),
NodeExecution: newNodeExecution(db, opts...),
WorkflowDraft: newWorkflowDraft(db, opts...),
WorkflowExecution: newWorkflowExecution(db, opts...),
WorkflowMeta: newWorkflowMeta(db, opts...),
WorkflowReference: newWorkflowReference(db, opts...),
WorkflowSnapshot: newWorkflowSnapshot(db, opts...),
WorkflowVersion: newWorkflowVersion(db, opts...),
db: db,
ConnectorWorkflowVersion: newConnectorWorkflowVersion(db, opts...),
AppConversationTemplateDraft: newAppConversationTemplateDraft(db, opts...),
AppConversationTemplateOnline: newAppConversationTemplateOnline(db, opts...),
AppDynamicConversationDraft: newAppDynamicConversationDraft(db, opts...),
AppDynamicConversationOnline: newAppDynamicConversationOnline(db, opts...),
AppStaticConversationDraft: newAppStaticConversationDraft(db, opts...),
AppStaticConversationOnline: newAppStaticConversationOnline(db, opts...),
ChatFlowRoleConfig: newChatFlowRoleConfig(db, opts...),
NodeExecution: newNodeExecution(db, opts...),
WorkflowDraft: newWorkflowDraft(db, opts...),
WorkflowExecution: newWorkflowExecution(db, opts...),
WorkflowMeta: newWorkflowMeta(db, opts...),
WorkflowReference: newWorkflowReference(db, opts...),
WorkflowSnapshot: newWorkflowSnapshot(db, opts...),
WorkflowVersion: newWorkflowVersion(db, opts...),
}
}
type Query struct {
db *gorm.DB
ConnectorWorkflowVersion connectorWorkflowVersion
NodeExecution nodeExecution
WorkflowDraft workflowDraft
WorkflowExecution workflowExecution
WorkflowMeta workflowMeta
WorkflowReference workflowReference
WorkflowSnapshot workflowSnapshot
WorkflowVersion workflowVersion
ConnectorWorkflowVersion connectorWorkflowVersion
AppConversationTemplateDraft appConversationTemplateDraft
AppConversationTemplateOnline appConversationTemplateOnline
AppDynamicConversationDraft appDynamicConversationDraft
AppDynamicConversationOnline appDynamicConversationOnline
AppStaticConversationDraft appStaticConversationDraft
AppStaticConversationOnline appStaticConversationOnline
ChatFlowRoleConfig chatFlowRoleConfig
NodeExecution nodeExecution
WorkflowDraft workflowDraft
WorkflowExecution workflowExecution
WorkflowMeta workflowMeta
WorkflowReference workflowReference
WorkflowSnapshot workflowSnapshot
WorkflowVersion workflowVersion
}
func (q *Query) Available() bool { return q.db != nil }
func (q *Query) clone(db *gorm.DB) *Query {
return &Query{
db: db,
ConnectorWorkflowVersion: q.ConnectorWorkflowVersion.clone(db),
NodeExecution: q.NodeExecution.clone(db),
WorkflowDraft: q.WorkflowDraft.clone(db),
WorkflowExecution: q.WorkflowExecution.clone(db),
WorkflowMeta: q.WorkflowMeta.clone(db),
WorkflowReference: q.WorkflowReference.clone(db),
WorkflowSnapshot: q.WorkflowSnapshot.clone(db),
WorkflowVersion: q.WorkflowVersion.clone(db),
db: db,
ConnectorWorkflowVersion: q.ConnectorWorkflowVersion.clone(db),
AppConversationTemplateDraft: q.AppConversationTemplateDraft.clone(db),
AppConversationTemplateOnline: q.AppConversationTemplateOnline.clone(db),
AppDynamicConversationDraft: q.AppDynamicConversationDraft.clone(db),
AppDynamicConversationOnline: q.AppDynamicConversationOnline.clone(db),
AppStaticConversationDraft: q.AppStaticConversationDraft.clone(db),
AppStaticConversationOnline: q.AppStaticConversationOnline.clone(db),
ChatFlowRoleConfig: q.ChatFlowRoleConfig.clone(db),
NodeExecution: q.NodeExecution.clone(db),
WorkflowDraft: q.WorkflowDraft.clone(db),
WorkflowExecution: q.WorkflowExecution.clone(db),
WorkflowMeta: q.WorkflowMeta.clone(db),
WorkflowReference: q.WorkflowReference.clone(db),
WorkflowSnapshot: q.WorkflowSnapshot.clone(db),
WorkflowVersion: q.WorkflowVersion.clone(db),
}
}
@@ -92,39 +127,60 @@ func (q *Query) WriteDB() *Query {
func (q *Query) ReplaceDB(db *gorm.DB) *Query {
return &Query{
db: db,
ConnectorWorkflowVersion: q.ConnectorWorkflowVersion.replaceDB(db),
NodeExecution: q.NodeExecution.replaceDB(db),
WorkflowDraft: q.WorkflowDraft.replaceDB(db),
WorkflowExecution: q.WorkflowExecution.replaceDB(db),
WorkflowMeta: q.WorkflowMeta.replaceDB(db),
WorkflowReference: q.WorkflowReference.replaceDB(db),
WorkflowSnapshot: q.WorkflowSnapshot.replaceDB(db),
WorkflowVersion: q.WorkflowVersion.replaceDB(db),
db: db,
ConnectorWorkflowVersion: q.ConnectorWorkflowVersion.replaceDB(db),
AppConversationTemplateDraft: q.AppConversationTemplateDraft.replaceDB(db),
AppConversationTemplateOnline: q.AppConversationTemplateOnline.replaceDB(db),
AppDynamicConversationDraft: q.AppDynamicConversationDraft.replaceDB(db),
AppDynamicConversationOnline: q.AppDynamicConversationOnline.replaceDB(db),
AppStaticConversationDraft: q.AppStaticConversationDraft.replaceDB(db),
AppStaticConversationOnline: q.AppStaticConversationOnline.replaceDB(db),
ChatFlowRoleConfig: q.ChatFlowRoleConfig.replaceDB(db),
NodeExecution: q.NodeExecution.replaceDB(db),
WorkflowDraft: q.WorkflowDraft.replaceDB(db),
WorkflowExecution: q.WorkflowExecution.replaceDB(db),
WorkflowMeta: q.WorkflowMeta.replaceDB(db),
WorkflowReference: q.WorkflowReference.replaceDB(db),
WorkflowSnapshot: q.WorkflowSnapshot.replaceDB(db),
WorkflowVersion: q.WorkflowVersion.replaceDB(db),
}
}
type queryCtx struct {
ConnectorWorkflowVersion IConnectorWorkflowVersionDo
NodeExecution INodeExecutionDo
WorkflowDraft IWorkflowDraftDo
WorkflowExecution IWorkflowExecutionDo
WorkflowMeta IWorkflowMetaDo
WorkflowReference IWorkflowReferenceDo
WorkflowSnapshot IWorkflowSnapshotDo
WorkflowVersion IWorkflowVersionDo
ConnectorWorkflowVersion IConnectorWorkflowVersionDo
AppConversationTemplateDraft IAppConversationTemplateDraftDo
AppConversationTemplateOnline IAppConversationTemplateOnlineDo
AppDynamicConversationDraft IAppDynamicConversationDraftDo
AppDynamicConversationOnline IAppDynamicConversationOnlineDo
AppStaticConversationDraft IAppStaticConversationDraftDo
AppStaticConversationOnline IAppStaticConversationOnlineDo
ChatFlowRoleConfig IChatFlowRoleConfigDo
NodeExecution INodeExecutionDo
WorkflowDraft IWorkflowDraftDo
WorkflowExecution IWorkflowExecutionDo
WorkflowMeta IWorkflowMetaDo
WorkflowReference IWorkflowReferenceDo
WorkflowSnapshot IWorkflowSnapshotDo
WorkflowVersion IWorkflowVersionDo
}
func (q *Query) WithContext(ctx context.Context) *queryCtx {
return &queryCtx{
ConnectorWorkflowVersion: q.ConnectorWorkflowVersion.WithContext(ctx),
NodeExecution: q.NodeExecution.WithContext(ctx),
WorkflowDraft: q.WorkflowDraft.WithContext(ctx),
WorkflowExecution: q.WorkflowExecution.WithContext(ctx),
WorkflowMeta: q.WorkflowMeta.WithContext(ctx),
WorkflowReference: q.WorkflowReference.WithContext(ctx),
WorkflowSnapshot: q.WorkflowSnapshot.WithContext(ctx),
WorkflowVersion: q.WorkflowVersion.WithContext(ctx),
ConnectorWorkflowVersion: q.ConnectorWorkflowVersion.WithContext(ctx),
AppConversationTemplateDraft: q.AppConversationTemplateDraft.WithContext(ctx),
AppConversationTemplateOnline: q.AppConversationTemplateOnline.WithContext(ctx),
AppDynamicConversationDraft: q.AppDynamicConversationDraft.WithContext(ctx),
AppDynamicConversationOnline: q.AppDynamicConversationOnline.WithContext(ctx),
AppStaticConversationDraft: q.AppStaticConversationDraft.WithContext(ctx),
AppStaticConversationOnline: q.AppStaticConversationOnline.WithContext(ctx),
ChatFlowRoleConfig: q.ChatFlowRoleConfig.WithContext(ctx),
NodeExecution: q.NodeExecution.WithContext(ctx),
WorkflowDraft: q.WorkflowDraft.WithContext(ctx),
WorkflowExecution: q.WorkflowExecution.WithContext(ctx),
WorkflowMeta: q.WorkflowMeta.WithContext(ctx),
WorkflowReference: q.WorkflowReference.WithContext(ctx),
WorkflowSnapshot: q.WorkflowSnapshot.WithContext(ctx),
WorkflowVersion: q.WorkflowVersion.WithContext(ctx),
}
}

View File

@@ -22,6 +22,8 @@ import (
"fmt"
"time"
"github.com/redis/go-redis/v9"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/infra/contract/cache"
@@ -38,6 +40,7 @@ const (
interruptEventListKeyPattern = "interrupt_event_list:%d"
interruptEventTTL = 24 * time.Hour // Example: expire after 24 hours
previousResumedEventKeyPattern = "previous_resumed_event:%d"
ConvToEventExecFormat = "conv_relate_info:%d"
)
// SaveInterruptEvents saves multiple interrupt events to the end of a Redis list.
@@ -246,3 +249,33 @@ func (i *interruptEventStoreImpl) ListInterruptEvents(ctx context.Context, wfExe
return events, nil
}
func (i *interruptEventStoreImpl) BindConvRelatedInfo(ctx context.Context, convID int64, info entity.ConvRelatedInfo) error {
data, err := sonic.Marshal(info)
if err != nil {
return err
}
result := i.redis.Set(ctx, fmt.Sprintf(ConvToEventExecFormat, convID), data, interruptEventTTL)
if result.Err() != nil {
return result.Err()
}
return nil
}
func (i *interruptEventStoreImpl) GetConvRelatedInfo(ctx context.Context, convID int64) (*entity.ConvRelatedInfo, bool, func() error, error) {
data, err := i.redis.Get(ctx, fmt.Sprintf(ConvToEventExecFormat, convID)).Bytes()
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, false, nil, nil
}
return nil, false, nil, err
}
rInfo := &entity.ConvRelatedInfo{}
err = sonic.UnmarshalString(string(data), rInfo)
if err != nil {
return nil, false, nil, err
}
return rInfo, true, func() error {
return i.redis.Del(ctx, fmt.Sprintf(ConvToEventExecFormat, convID)).Err()
}, nil
}

View File

@@ -70,10 +70,15 @@ type RepositoryImpl struct {
workflow.ExecuteHistoryStore
builtinModel cm.BaseChatModel
workflow.WorkflowConfig
workflow.Suggester
}
func NewRepository(idgen idgen.IDGenerator, db *gorm.DB, redis cache.Cmdable, tos storage.Storage,
cpStore einoCompose.CheckPointStore, chatModel cm.BaseChatModel, workflowConfig workflow.WorkflowConfig) workflow.Repository {
cpStore einoCompose.CheckPointStore, chatModel cm.BaseChatModel, workflowConfig workflow.WorkflowConfig) (workflow.Repository, error) {
sg, err := NewSuggester(chatModel)
if err != nil {
return nil, err
}
return &RepositoryImpl{
IDGenerator: idgen,
query: query.Use(db),
@@ -90,9 +95,12 @@ func NewRepository(idgen idgen.IDGenerator, db *gorm.DB, redis cache.Cmdable, to
query: query.Use(db),
redis: redis,
},
builtinModel: chatModel,
Suggester: sg,
WorkflowConfig: workflowConfig,
}
}, nil
}
func (r *RepositoryImpl) CreateMeta(ctx context.Context, meta *vo.Meta) (int64, error) {
@@ -320,13 +328,16 @@ func (r *RepositoryImpl) CreateVersion(ctx context.Context, id int64, info *vo.V
func (r *RepositoryImpl) CreateOrUpdateDraft(ctx context.Context, id int64, draft *vo.DraftInfo) error {
d := &model.WorkflowDraft{
ID: id,
Canvas: draft.Canvas,
InputParams: draft.InputParamsStr,
OutputParams: draft.OutputParamsStr,
Modified: draft.Modified,
TestRunSuccess: draft.TestRunSuccess,
CommitID: draft.CommitID,
ID: id,
Canvas: draft.Canvas,
InputParams: draft.InputParamsStr,
OutputParams: draft.OutputParamsStr,
CommitID: draft.CommitID,
}
if draft.DraftMeta != nil {
d.Modified = draft.DraftMeta.Modified
d.TestRunSuccess = draft.DraftMeta.TestRunSuccess
}
if err := r.query.WorkflowDraft.WithContext(ctx).Save(d); err != nil {
@@ -500,6 +511,10 @@ func (r *RepositoryImpl) UpdateMeta(ctx context.Context, id int64, metaUpdate *v
expressions = append(expressions, r.query.WorkflowMeta.LatestVersion.Value(*metaUpdate.LatestPublishedVersion))
}
if metaUpdate.WorkflowMode != nil {
expressions = append(expressions, r.query.WorkflowMeta.Mode.Value(int32(*metaUpdate.WorkflowMode)))
}
if len(expressions) == 0 {
return nil
}
@@ -551,10 +566,13 @@ func (r *RepositoryImpl) GetEntity(ctx context.Context, policy *vo.GetPolicy) (_
draftMeta = draft.DraftMeta
commitID = draft.CommitID
case workflowModel.FromSpecificVersion:
v, err := r.GetVersion(ctx, policy.ID, policy.Version)
v, existed, err := r.GetVersion(ctx, policy.ID, policy.Version)
if err != nil {
return nil, err
}
if !existed {
return nil, vo.WrapError(errno.ErrWorkflowNotFound, fmt.Errorf("workflow version %s not found for ID %d: %w", policy.Version, policy.ID, err), errorx.KV("id", strconv.FormatInt(policy.ID, 10)))
}
canvas = v.Canvas
inputParams = v.InputParamsStr
outputParams = v.OutputParamsStr
@@ -604,7 +622,117 @@ func (r *RepositoryImpl) GetEntity(ctx context.Context, policy *vo.GetPolicy) (_
}, nil
}
func (r *RepositoryImpl) GetVersion(ctx context.Context, id int64, version string) (_ *vo.VersionInfo, err error) {
func (r *RepositoryImpl) CreateChatFlowRoleConfig(ctx context.Context, chatFlowRole *entity.ChatFlowRole) (int64, error) {
id, err := r.GenID(ctx)
if err != nil {
return 0, vo.WrapError(errno.ErrIDGenError, err)
}
chatFlowRoleConfig := &model.ChatFlowRoleConfig{
ID: id,
WorkflowID: chatFlowRole.WorkflowID,
Name: chatFlowRole.Name,
Description: chatFlowRole.Description,
Avatar: chatFlowRole.AvatarUri,
AudioConfig: chatFlowRole.AudioConfig,
BackgroundImageInfo: chatFlowRole.BackgroundImageInfo,
OnboardingInfo: chatFlowRole.OnboardingInfo,
SuggestReplyInfo: chatFlowRole.SuggestReplyInfo,
UserInputConfig: chatFlowRole.UserInputConfig,
CreatorID: chatFlowRole.CreatorID,
Version: chatFlowRole.Version,
}
if err := r.query.ChatFlowRoleConfig.WithContext(ctx).Create(chatFlowRoleConfig); err != nil {
return 0, vo.WrapError(errno.ErrDatabaseError, fmt.Errorf("create chat flow role: %w", err))
}
return id, nil
}
func (r *RepositoryImpl) UpdateChatFlowRoleConfig(ctx context.Context, workflowID int64, chatFlowRole *vo.ChatFlowRoleUpdate) error {
var expressions []field.AssignExpr
if chatFlowRole.Name != nil {
expressions = append(expressions, r.query.ChatFlowRoleConfig.Name.Value(*chatFlowRole.Name))
}
if chatFlowRole.Description != nil {
expressions = append(expressions, r.query.ChatFlowRoleConfig.Description.Value(*chatFlowRole.Description))
}
if chatFlowRole.AvatarUri != nil {
expressions = append(expressions, r.query.ChatFlowRoleConfig.Avatar.Value(*chatFlowRole.AvatarUri))
}
if chatFlowRole.AudioConfig != nil {
expressions = append(expressions, r.query.ChatFlowRoleConfig.AudioConfig.Value(*chatFlowRole.AudioConfig))
}
if chatFlowRole.BackgroundImageInfo != nil {
expressions = append(expressions, r.query.ChatFlowRoleConfig.BackgroundImageInfo.Value(*chatFlowRole.BackgroundImageInfo))
}
if chatFlowRole.OnboardingInfo != nil {
expressions = append(expressions, r.query.ChatFlowRoleConfig.OnboardingInfo.Value(*chatFlowRole.OnboardingInfo))
}
if chatFlowRole.SuggestReplyInfo != nil {
expressions = append(expressions, r.query.ChatFlowRoleConfig.SuggestReplyInfo.Value(*chatFlowRole.SuggestReplyInfo))
}
if chatFlowRole.UserInputConfig != nil {
expressions = append(expressions, r.query.ChatFlowRoleConfig.UserInputConfig.Value(*chatFlowRole.UserInputConfig))
}
if len(expressions) == 0 {
return nil
}
_, err := r.query.ChatFlowRoleConfig.WithContext(ctx).Where(r.query.ChatFlowRoleConfig.WorkflowID.Eq(workflowID)).
UpdateColumnSimple(expressions...)
if err != nil {
return vo.WrapError(errno.ErrDatabaseError, fmt.Errorf("update chat flow role: %w", err))
}
return nil
}
func (r *RepositoryImpl) GetChatFlowRoleConfig(ctx context.Context, workflowID int64, version string) (_ *entity.ChatFlowRole, err error, isExist bool) {
defer func() {
if err != nil {
err = vo.WrapIfNeeded(errno.ErrDatabaseError, err)
}
}()
role := &model.ChatFlowRoleConfig{}
if version != "" {
role, err = r.query.ChatFlowRoleConfig.WithContext(ctx).Where(r.query.ChatFlowRoleConfig.WorkflowID.Eq(workflowID), r.query.ChatFlowRoleConfig.Version.Eq(version)).First()
} else {
role, err = r.query.ChatFlowRoleConfig.WithContext(ctx).Where(r.query.ChatFlowRoleConfig.WorkflowID.Eq(workflowID)).First()
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err, false
}
return nil, fmt.Errorf("failed to get chat flow role for chatflowID %d: %w", workflowID, err), true
}
res := &entity.ChatFlowRole{
ID: role.ID,
WorkflowID: role.WorkflowID,
Name: role.Name,
Description: role.Description,
AvatarUri: role.Avatar,
AudioConfig: role.AudioConfig,
BackgroundImageInfo: role.BackgroundImageInfo,
OnboardingInfo: role.OnboardingInfo,
SuggestReplyInfo: role.SuggestReplyInfo,
UserInputConfig: role.UserInputConfig,
CreatorID: role.CreatorID,
CreatedAt: time.UnixMilli(role.CreatedAt),
}
if role.UpdatedAt > 0 {
res.UpdatedAt = time.UnixMilli(role.UpdatedAt)
}
return res, err, true
}
func (r *RepositoryImpl) DeleteChatFlowRoleConfig(ctx context.Context, id int64, workflowID int64) error {
_, err := r.query.ChatFlowRoleConfig.WithContext(ctx).Where(r.query.ChatFlowRoleConfig.ID.Eq(id), r.query.ChatFlowRoleConfig.WorkflowID.Eq(workflowID)).Delete()
return err
}
func (r *RepositoryImpl) GetVersion(ctx context.Context, id int64, version string) (_ *vo.VersionInfo, existed bool, err error) {
defer func() {
if err != nil {
err = vo.WrapIfNeeded(errno.ErrDatabaseError, err)
@@ -616,9 +744,9 @@ func (r *RepositoryImpl) GetVersion(ctx context.Context, id int64, version strin
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, vo.WrapError(errno.ErrWorkflowNotFound, fmt.Errorf("workflow version %s not found for ID %d: %w", version, id, err), errorx.KV("id", strconv.FormatInt(id, 10)))
return nil, false, nil
}
return nil, fmt.Errorf("failed to get workflow version %s for ID %d: %w", version, id, err)
return nil, false, fmt.Errorf("failed to get workflow version %s for ID %d: %w", version, id, err)
}
return &vo.VersionInfo{
@@ -634,7 +762,29 @@ func (r *RepositoryImpl) GetVersion(ctx context.Context, id int64, version strin
OutputParamsStr: wfVersion.OutputParams,
},
CommitID: wfVersion.CommitID,
}, nil
}, true, nil
}
func (r *RepositoryImpl) GetVersionListByConnectorAndWorkflowID(ctx context.Context, connectorID, workflowID int64, limit int) (_ []string, err error) {
if limit <= 0 {
return nil, vo.WrapError(errno.ErrInvalidParameter, errors.New("limit must be greater than 0"))
}
connectorWorkflowVersion := r.query.ConnectorWorkflowVersion
vl, err := connectorWorkflowVersion.WithContext(ctx).
Where(connectorWorkflowVersion.ConnectorID.Eq(connectorID),
connectorWorkflowVersion.WorkflowID.Eq(workflowID)).
Order(connectorWorkflowVersion.CreatedAt.Desc()).
Limit(limit).
Find()
if err != nil {
return nil, vo.WrapError(errno.ErrDatabaseError, err)
}
var versionList []string
for _, v := range vl {
versionList = append(versionList, v.Version)
}
return versionList, nil
}
func (r *RepositoryImpl) IsApplicationConnectorWorkflowVersion(ctx context.Context, connectorID, workflowID int64, version string) (b bool, err error) {
@@ -767,6 +917,10 @@ func (r *RepositoryImpl) MGetDrafts(ctx context.Context, policy *vo.MGetPolicy)
conditions = append(conditions, r.query.WorkflowMeta.AppID.Eq(0))
}
if q.Mode != nil {
conditions = append(conditions, r.query.WorkflowMeta.Mode.Eq(int32(*q.Mode)))
}
type combinedDraft struct {
model.WorkflowDraft
Name string `gorm:"column:name"`
@@ -933,6 +1087,10 @@ func (r *RepositoryImpl) MGetLatestVersion(ctx context.Context, policy *vo.MGetP
conditions = append(conditions, r.query.WorkflowMeta.AppID.Eq(0))
}
if q.Mode != nil {
conditions = append(conditions, r.query.WorkflowMeta.Mode.Eq(int32(*q.Mode)))
}
type combinedVersion struct {
model.WorkflowMeta
Version string `gorm:"column:version"` // release version
@@ -1157,6 +1315,10 @@ func (r *RepositoryImpl) MGetMetas(ctx context.Context, query *vo.MetaQuery) (
conditions = append(conditions, r.query.WorkflowMeta.AppID.Eq(0))
}
if query.Mode != nil {
conditions = append(conditions, r.query.WorkflowMeta.Mode.Eq(int32(*query.Mode)))
}
var result []*model.WorkflowMeta
workflowMetaDo := r.query.WorkflowMeta.WithContext(ctx).Debug().Where(conditions...)
@@ -1520,6 +1682,7 @@ func (r *RepositoryImpl) CopyWorkflow(ctx context.Context, workflowID int64, pol
IconURI: wfMeta.IconURI,
Desc: wfMeta.Description,
AppID: ternary.IFElse(wfMeta.AppID == 0, (*int64)(nil), ptr.Of(wfMeta.AppID)),
Mode: workflowModel.WorkflowMode(wfMeta.Mode),
},
CanvasInfo: &vo.CanvasInfo{
Canvas: wfDraft.Canvas,
@@ -1594,6 +1757,10 @@ func (r *RepositoryImpl) GetKnowledgeRecallChatModel() cm.BaseChatModel {
return r.builtinModel
}
func (r *RepositoryImpl) GetObjectUrl(ctx context.Context, objectKey string, opts ...storage.GetOptFn) (string, error) {
return r.tos.GetObjectUrl(ctx, objectKey, opts...)
}
func filterDisabledAPIParameters(parametersCfg []*workflow3.APIParameter, m map[string]any) map[string]any {
result := make(map[string]any, len(m))
responseParameterMap := slices.ToMap(parametersCfg, func(p *workflow3.APIParameter) (string, *workflow3.APIParameter) {

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package repo
import (
"context"
"regexp"
"github.com/cloudwego/eino/components/model"
"github.com/cloudwego/eino/components/prompt"
"github.com/cloudwego/eino/compose"
einoCompose "github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/schema"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
)
const SUGGESTION_PROMPT = `
# Role
You are an AI assistant that quickly generates 3 relevant follow-up questions.
# Task
Analyze the user's question and the assistant's answer to suggest 3 unique, concise follow-up questions.
**IMPORTANT**: The assistant's answer can be very long. To be fast, focus only on the main ideas and topics in the answer. Do not analyze the full text in detail.
### Persona
{{ suggest_persona }}
## Output Format
- Return **only** a single JSON string array.
- Example: ["What is the history?", "How does it work?", "What are the benefits?"]
- The questions must be in the same language as the user's input.
`
type suggesterV3 struct {
r einoCompose.Runnable[*vo.SuggestInfo, []string]
}
type state struct {
userMessage *schema.Message
answer *schema.Message
}
var suggestRegexp = regexp.MustCompile(`\[(.*?)\]`)
func NewSuggester(chatModel model.BaseChatModel) (workflow.Suggester, error) {
chain := einoCompose.NewChain[*vo.SuggestInfo, []string](einoCompose.WithGenLocalState(func(ctx context.Context) (s *state) {
return &state{}
}))
r, err := chain.AppendLambda(einoCompose.InvokableLambda(func(ctx context.Context, input *vo.SuggestInfo) (output map[string]any, err error) {
_ = compose.ProcessState(ctx, func(ctx context.Context, s *state) error {
s.userMessage = input.UserInput
s.answer = input.AnswerInput
return nil
})
output = map[string]any{}
if input.PersonaInput != nil {
output["persona_input"] = *input.PersonaInput
}
return
})).AppendChatTemplate(prompt.FromMessages(schema.Jinja2, schema.SystemMessage(SUGGESTION_PROMPT))).AppendChatModel(chatModel,
compose.WithStatePreHandler(func(ctx context.Context, in []*schema.Message, state *state) ([]*schema.Message, error) {
return append(in, []*schema.Message{state.userMessage, state.answer}...), nil
})).AppendLambda(einoCompose.InvokableLambda(func(ctx context.Context, input *schema.Message) (output []string, err error) {
content := suggestRegexp.FindString(input.Content)
if len(content) == 0 {
return
}
suggests := make([]string, 0)
err = sonic.UnmarshalString(content, &suggests)
if err != nil {
logs.CtxErrorf(ctx, "Failed unmarshalling suggestions: %s", input.Content)
}
return suggests, nil
})).Compile(context.Background())
if err != nil {
return nil, err
}
return &suggesterV3{r: r}, nil
}
func (s *suggesterV3) Suggest(ctx context.Context, info *vo.SuggestInfo) ([]string, error) {
return s.r.Invoke(ctx, info)
}

View File

@@ -0,0 +1,490 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package service
import (
"context"
"fmt"
"github.com/coze-dev/coze-studio/backend/api/model/conversation/common"
conventity "github.com/coze-dev/coze-studio/backend/domain/conversation/conversation/entity"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
"github.com/coze-dev/coze-studio/backend/pkg/taskgroup"
workflow2 "github.com/coze-dev/coze-studio/backend/api/model/workflow"
crossconversation "github.com/coze-dev/coze-studio/backend/crossdomain/contract/conversation"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/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/sonic"
"github.com/coze-dev/coze-studio/backend/types/consts"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type conversationImpl struct {
repo workflow.Repository
}
func (c *conversationImpl) CreateDraftConversationTemplate(ctx context.Context, template *vo.CreateConversationTemplateMeta) (int64, error) {
var (
spaceID = template.SpaceID
appID = template.AppID
name = template.Name
userID = template.UserID
)
existed, err := c.IsDraftConversationNameExist(ctx, appID, userID, template.Name)
if err != nil {
return 0, err
}
if existed {
return 0, vo.WrapError(errno.ErrConversationNameIsDuplicated, fmt.Errorf("conversation name %s exists", name), errorx.KV("name", name))
}
return c.repo.CreateDraftConversationTemplate(ctx, &vo.CreateConversationTemplateMeta{
SpaceID: spaceID,
AppID: appID,
Name: name,
UserID: userID,
})
}
func (c *conversationImpl) IsDraftConversationNameExist(ctx context.Context, appID int64, userID int64, name string) (bool, error) {
_, existed, err := c.repo.GetDynamicConversationByName(ctx, vo.Draft, appID, consts.CozeConnectorID, userID, name)
if err != nil {
return false, err
}
if existed {
return true, nil
}
_, existed, err = c.repo.GetConversationTemplate(ctx, vo.Draft, vo.GetConversationTemplatePolicy{AppID: ptr.Of(appID), Name: ptr.Of(name)})
if err != nil {
return false, err
}
if existed {
return true, nil
}
return false, nil
}
func (c *conversationImpl) UpdateDraftConversationTemplateName(ctx context.Context, appID int64, userID int64, templateID int64, modifiedName string) error {
template, existed, err := c.repo.GetConversationTemplate(ctx, vo.Draft, vo.GetConversationTemplatePolicy{TemplateID: ptr.Of(templateID)})
if err != nil {
return err
}
if existed && template.Name == modifiedName {
return nil
}
existed, err = c.IsDraftConversationNameExist(ctx, appID, userID, modifiedName)
if err != nil {
return err
}
if existed {
return vo.WrapError(errno.ErrConversationNameIsDuplicated, fmt.Errorf("conversation name %s exists", modifiedName), errorx.KV("name", modifiedName))
}
wfs, err := c.findReplaceWorkflowByConversationName(ctx, appID, template.Name)
if err != nil {
return err
}
err = c.replaceWorkflowsConversationName(ctx, wfs, slices.ToMap(wfs, func(e *entity.Workflow) (int64, string) {
return e.ID, modifiedName
}))
if err != nil {
return err
}
return c.repo.UpdateDraftConversationTemplateName(ctx, templateID, modifiedName)
}
func (c *conversationImpl) CheckWorkflowsToReplace(ctx context.Context, appID int64, templateID int64) ([]*entity.Workflow, error) {
template, existed, err := c.repo.GetConversationTemplate(ctx, vo.Draft, vo.GetConversationTemplatePolicy{TemplateID: ptr.Of(templateID)})
if err != nil {
return nil, err
}
if existed {
return c.findReplaceWorkflowByConversationName(ctx, appID, template.Name)
}
return []*entity.Workflow{}, nil
}
func (c *conversationImpl) DeleteDraftConversationTemplate(ctx context.Context, templateID int64, wfID2ConversationName map[int64]string) (int64, error) {
if len(wfID2ConversationName) == 0 {
return c.repo.DeleteDraftConversationTemplate(ctx, templateID)
}
workflowIDs := make([]int64, 0)
for id := range wfID2ConversationName {
workflowIDs = append(workflowIDs, id)
}
wfs, _, err := c.repo.MGetDrafts(ctx, &vo.MGetPolicy{
MetaQuery: vo.MetaQuery{
IDs: workflowIDs,
},
QType: workflowModel.FromDraft,
})
if err != nil {
return 0, err
}
err = c.replaceWorkflowsConversationName(ctx, wfs, wfID2ConversationName)
if err != nil {
return 0, err
}
return c.repo.DeleteDraftConversationTemplate(ctx, templateID)
}
func (c *conversationImpl) ListConversationTemplate(ctx context.Context, env vo.Env, policy *vo.ListConversationTemplatePolicy) ([]*entity.ConversationTemplate, error) {
var (
err error
templates []*entity.ConversationTemplate
appID = policy.AppID
)
templates, err = c.repo.ListConversationTemplate(ctx, env, &vo.ListConversationTemplatePolicy{
AppID: appID,
Page: policy.Page,
NameLike: policy.NameLike,
Version: policy.Version,
})
if err != nil {
return nil, err
}
return templates, nil
}
func (c *conversationImpl) MGetStaticConversation(ctx context.Context, env vo.Env, userID, connectorID int64, templateIDs []int64) ([]*entity.StaticConversation, error) {
return c.repo.MGetStaticConversation(ctx, env, userID, connectorID, templateIDs)
}
func (c *conversationImpl) ListDynamicConversation(ctx context.Context, env vo.Env, policy *vo.ListConversationPolicy) ([]*entity.DynamicConversation, error) {
return c.repo.ListDynamicConversation(ctx, env, policy)
}
func (c *conversationImpl) ReleaseConversationTemplate(ctx context.Context, appID int64, version string) error {
templates, err := c.repo.ListConversationTemplate(ctx, vo.Draft, &vo.ListConversationTemplatePolicy{
AppID: appID,
})
if err != nil {
return err
}
if len(templates) == 0 {
return nil
}
return c.repo.BatchCreateOnlineConversationTemplate(ctx, templates, version)
}
func (c *conversationImpl) InitApplicationDefaultConversationTemplate(ctx context.Context, spaceID, appID int64, userID int64) error {
_, err := c.repo.CreateDraftConversationTemplate(ctx, &vo.CreateConversationTemplateMeta{
AppID: appID,
SpaceID: spaceID,
UserID: userID,
Name: "Default",
})
if err != nil {
return err
}
return nil
}
func (c *conversationImpl) findReplaceWorkflowByConversationName(ctx context.Context, appID int64, name string) ([]*entity.Workflow, error) {
wfs, _, err := c.repo.MGetDrafts(ctx, &vo.MGetPolicy{
QType: workflowModel.FromDraft,
MetaQuery: vo.MetaQuery{
AppID: ptr.Of(appID),
Mode: ptr.Of(workflow2.WorkflowMode_ChatFlow),
},
})
if err != nil {
return nil, err
}
shouldReplacedWorkflow := func(nodes []*vo.Node) (bool, error) {
var startNode *vo.Node
for _, node := range nodes {
if node.Type == entity.NodeTypeEntry.IDStr() {
startNode = node
}
}
if startNode == nil {
return false, fmt.Errorf("start node not found for block type")
}
for _, vAny := range startNode.Data.Outputs {
v, err := vo.ParseVariable(vAny)
if err != nil {
return false, err
}
if v.Name == "CONVERSATION_NAME" && v.DefaultValue == name {
return true, nil
}
}
return false, nil
}
shouldReplacedWorkflows := make([]*entity.Workflow, 0)
for idx := range wfs {
wf := wfs[idx]
canvas := &vo.Canvas{}
err = sonic.UnmarshalString(wf.Canvas, canvas)
if err != nil {
return nil, err
}
ok, err := shouldReplacedWorkflow(canvas.Nodes)
if err != nil {
return nil, err
}
if ok {
shouldReplacedWorkflows = append(shouldReplacedWorkflows, wf)
}
}
return shouldReplacedWorkflows, nil
}
func (c *conversationImpl) replaceWorkflowsConversationName(ctx context.Context, wfs []*entity.Workflow, workflowID2ConversionName map[int64]string) error {
replaceConversionName := func(nodes []*vo.Node, conversionName string) error {
var startNode *vo.Node
for _, node := range nodes {
if node.Type == entity.NodeTypeEntry.IDStr() {
startNode = node
}
}
if startNode == nil {
return fmt.Errorf("start node not found for block type")
}
for idx, vAny := range startNode.Data.Outputs {
v, err := vo.ParseVariable(vAny)
if err != nil {
return err
}
if v.Name == "CONVERSATION_NAME" {
v.DefaultValue = conversionName
}
startNode.Data.Outputs[idx] = v
}
return nil
}
tg := taskgroup.NewTaskGroup(ctx, len(wfs))
for _, wf := range wfs {
wfEntity := wf
tg.Go(func() error {
canvas := &vo.Canvas{}
err := sonic.UnmarshalString(wfEntity.Canvas, canvas)
if err != nil {
return err
}
conversationName := workflowID2ConversionName[wfEntity.ID]
err = replaceConversionName(canvas.Nodes, conversationName)
if err != nil {
return err
}
replaceCanvas, err := sonic.MarshalString(canvas)
if err != nil {
return err
}
err = c.repo.CreateOrUpdateDraft(ctx, wfEntity.ID, &vo.DraftInfo{
DraftMeta: &vo.DraftMeta{
TestRunSuccess: false,
Modified: true,
},
Canvas: replaceCanvas,
})
if err != nil {
return err
}
return nil
})
}
err := tg.Wait()
if err != nil {
return err
}
return nil
}
func (c *conversationImpl) DeleteDynamicConversation(ctx context.Context, env vo.Env, templateID int64) (int64, error) {
return c.repo.DeleteDynamicConversation(ctx, env, templateID)
}
func (c *conversationImpl) GetOrCreateConversation(ctx context.Context, env vo.Env, appID, connectorID, userID int64, conversationName string) (int64, int64, error) {
t, existed, err := c.repo.GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: ptr.Of(appID),
Name: ptr.Of(conversationName),
})
if err != nil {
return 0, 0, err
}
conversationIDGenerator := workflow.ConversationIDGenerator(func(ctx context.Context, appID int64, userID, connectorID int64) (*conventity.Conversation, error) {
return crossconversation.DefaultSVC().CreateConversation(ctx, &conventity.CreateMeta{
AgentID: appID,
UserID: userID,
ConnectorID: connectorID,
Scene: common.Scene_SceneWorkflow,
})
})
if existed {
conversationID, sectionID, _, err := c.repo.GetOrCreateStaticConversation(ctx, env, conversationIDGenerator, &vo.CreateStaticConversation{
AppID: appID,
ConnectorID: connectorID,
UserID: userID,
TemplateID: t.TemplateID,
})
if err != nil {
return 0, 0, err
}
return conversationID, sectionID, nil
}
conversationID, sectionID, _, err := c.repo.GetOrCreateDynamicConversation(ctx, env, conversationIDGenerator, &vo.CreateDynamicConversation{
AppID: appID,
ConnectorID: connectorID,
UserID: userID,
Name: conversationName,
})
if err != nil {
return 0, 0, err
}
return conversationID, sectionID, nil
}
func (c *conversationImpl) UpdateConversation(ctx context.Context, env vo.Env, appID, connectorID, userID int64, conversationName string) (int64, error) {
t, existed, err := c.repo.GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: ptr.Of(appID),
Name: ptr.Of(conversationName),
})
if err != nil {
return 0, err
}
if existed {
conv, err := crossconversation.DefaultSVC().CreateConversation(ctx, &conventity.CreateMeta{
AgentID: appID,
UserID: userID,
ConnectorID: connectorID,
Scene: common.Scene_SceneWorkflow,
})
if err != nil {
return 0, err
}
if conv == nil {
return 0, fmt.Errorf("create conversation failed")
}
err = c.repo.UpdateStaticConversation(ctx, env, t.TemplateID, connectorID, userID, conv.ID)
if err != nil {
return 0, err
}
return conv.ID, nil
}
dy, existed, err := c.repo.GetDynamicConversationByName(ctx, env, appID, connectorID, userID, conversationName)
if err != nil {
return 0, err
}
if !existed {
return 0, fmt.Errorf("conversation name %v not found", conversationName)
}
conv, err := crossconversation.DefaultSVC().CreateConversation(ctx, &conventity.CreateMeta{
AgentID: appID,
UserID: userID,
ConnectorID: connectorID,
Scene: common.Scene_SceneWorkflow,
})
if err != nil {
return 0, err
}
if conv == nil {
return 0, fmt.Errorf("create conversation failed")
}
err = c.repo.UpdateDynamicConversation(ctx, env, dy.ConversationID, conv.ID)
if err != nil {
return 0, err
}
return conv.ID, nil
}
func (c *conversationImpl) GetTemplateByName(ctx context.Context, env vo.Env, appID int64, templateName string) (*entity.ConversationTemplate, bool, error) {
return c.repo.GetConversationTemplate(ctx, env, vo.GetConversationTemplatePolicy{
AppID: ptr.Of(appID),
Name: ptr.Of(templateName),
})
}
func (c *conversationImpl) GetDynamicConversationByName(ctx context.Context, env vo.Env, appID, connectorID, userID int64, name string) (*entity.DynamicConversation, bool, error) {
return c.repo.GetDynamicConversationByName(ctx, env, appID, connectorID, userID, name)
}
func (c *conversationImpl) GetConversationNameByID(ctx context.Context, env vo.Env, appID, connectorID, conversationID int64) (string, bool, error) {
sc, existed, err := c.repo.GetStaticConversationByID(ctx, env, appID, connectorID, conversationID)
if err != nil {
return "", false, err
}
if existed {
return sc, true, nil
}
dc, existed, err := c.repo.GetDynamicConversationByID(ctx, env, appID, connectorID, conversationID)
if err != nil {
return "", false, err
}
if existed {
return dc.Name, true, nil
}
return "", false, nil
}
func (c *conversationImpl) Suggest(ctx context.Context, input *vo.SuggestInfo) ([]string, error) {
return c.repo.Suggest(ctx, input)
}

View File

@@ -26,6 +26,8 @@ import (
"github.com/cloudwego/eino/schema"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
workflowapimodel "github.com/coze-dev/coze-studio/backend/api/model/workflow"
crossmessage "github.com/coze-dev/coze-studio/backend/crossdomain/contract/message"
"github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
@@ -62,6 +64,8 @@ func (i *impl) SyncExecute(ctx context.Context, config workflowModel.ExecuteConf
return nil, "", err
}
config.WorkflowMode = wfEntity.Mode
isApplicationWorkflow := wfEntity.AppID != nil
if isApplicationWorkflow && config.Mode == workflowModel.ExecuteModeRelease {
err = i.checkApplicationWorkflowReleaseVersion(ctx, *wfEntity.AppID, config.ConnectorID, config.ID, config.Version)
@@ -207,6 +211,8 @@ func (i *impl) AsyncExecute(ctx context.Context, config workflowModel.ExecuteCon
return 0, err
}
config.WorkflowMode = wfEntity.Mode
isApplicationWorkflow := wfEntity.AppID != nil
if isApplicationWorkflow && config.Mode == workflowModel.ExecuteModeRelease {
err = i.checkApplicationWorkflowReleaseVersion(ctx, *wfEntity.AppID, config.ConnectorID, config.ID, config.Version)
@@ -292,6 +298,8 @@ func (i *impl) AsyncExecuteNode(ctx context.Context, nodeID string, config workf
return 0, err
}
config.WorkflowMode = wfEntity.Mode
isApplicationWorkflow := wfEntity.AppID != nil
if isApplicationWorkflow && config.Mode == workflowModel.ExecuteModeRelease {
err = i.checkApplicationWorkflowReleaseVersion(ctx, *wfEntity.AppID, config.ConnectorID, config.ID, config.Version)
@@ -300,6 +308,30 @@ func (i *impl) AsyncExecuteNode(ctx context.Context, nodeID string, config workf
}
}
historyRounds := int64(0)
if config.WorkflowMode == workflowapimodel.WorkflowMode_ChatFlow {
historyRounds, err = getHistoryRoundsFromNode(ctx, wfEntity, nodeID, i.repo)
if err != nil {
return 0, err
}
}
if historyRounds > 0 {
messages, scMessages, err := i.prefetchChatHistory(ctx, config, historyRounds)
if err != nil {
logs.CtxErrorf(ctx, "failed to prefetch chat history: %v", err)
}
if len(messages) > 0 {
config.ConversationHistory = messages
}
if len(scMessages) > 0 {
config.ConversationHistorySchemaMessages = scMessages
}
}
c := &vo.Canvas{}
if err = sonic.UnmarshalString(wfEntity.Canvas, c); err != nil {
return 0, fmt.Errorf("failed to unmarshal canvas: %w", err)
@@ -375,6 +407,8 @@ func (i *impl) StreamExecute(ctx context.Context, config workflowModel.ExecuteCo
return nil, err
}
config.WorkflowMode = wfEntity.Mode
isApplicationWorkflow := wfEntity.AppID != nil
if isApplicationWorkflow && config.Mode == workflowModel.ExecuteModeRelease {
err = i.checkApplicationWorkflowReleaseVersion(ctx, *wfEntity.AppID, config.ConnectorID, config.ID, config.Version)
@@ -383,6 +417,29 @@ func (i *impl) StreamExecute(ctx context.Context, config workflowModel.ExecuteCo
}
}
historyRounds := int64(0)
if config.WorkflowMode == workflowapimodel.WorkflowMode_ChatFlow {
historyRounds, err = i.calculateMaxChatHistoryRounds(ctx, wfEntity, i.repo)
if err != nil {
return nil, err
}
}
if historyRounds > 0 {
messages, scMessages, err := i.prefetchChatHistory(ctx, config, historyRounds)
if err != nil {
logs.CtxErrorf(ctx, "failed to prefetch chat history: %v", err)
}
if len(messages) > 0 {
config.ConversationHistory = messages
}
if len(scMessages) > 0 {
config.ConversationHistorySchemaMessages = scMessages
}
}
c := &vo.Canvas{}
if err = sonic.UnmarshalString(wfEntity.Canvas, c); err != nil {
return nil, fmt.Errorf("failed to unmarshal canvas: %w", err)
@@ -718,6 +775,7 @@ func (i *impl) AsyncResume(ctx context.Context, req *entity.ResumeRequest, confi
config.AppID = wfExe.AppID
config.AgentID = wfExe.AgentID
config.CommitID = wfExe.CommitID
config.WorkflowMode = wfEntity.Mode
if config.ConnectorID == 0 {
config.ConnectorID = wfExe.ConnectorID
@@ -859,6 +917,7 @@ func (i *impl) StreamResume(ctx context.Context, req *entity.ResumeRequest, conf
config.AppID = wfExe.AppID
config.AgentID = wfExe.AgentID
config.CommitID = wfExe.CommitID
config.WorkflowMode = wfEntity.Mode
if config.ConnectorID == 0 {
config.ConnectorID = wfExe.ConnectorID
@@ -937,3 +996,73 @@ func (i *impl) checkApplicationWorkflowReleaseVersion(ctx context.Context, appID
return nil
}
const maxHistoryRounds int64 = 30
func (i *impl) calculateMaxChatHistoryRounds(ctx context.Context, wfEntity *entity.Workflow, repo workflow.Repository) (int64, error) {
if wfEntity == nil {
return 0, nil
}
maxRounds, err := getMaxHistoryRoundsRecursively(ctx, wfEntity, repo)
if err != nil {
return 0, err
}
return min(maxRounds, maxHistoryRounds), nil
}
func (i *impl) prefetchChatHistory(ctx context.Context, config workflowModel.ExecuteConfig, historyRounds int64) ([]*crossmessage.WfMessage, []*schema.Message, error) {
convID := config.ConversationID
agentID := config.AgentID
appID := config.AppID
userID := config.Operator
sectionID := config.SectionID
if sectionID == nil {
logs.CtxWarnf(ctx, "SectionID is nil, skipping chat history")
return nil, nil, nil
}
if convID == nil || *convID == 0 {
logs.CtxWarnf(ctx, "ConversationID is 0 or nil, skipping chat history")
return nil, nil, nil
}
var resolvedAppID int64
if appID != nil {
resolvedAppID = *appID
} else if agentID != nil {
resolvedAppID = *agentID
} else {
logs.CtxWarnf(ctx, "AppID and AgentID are both nil, skipping chat history")
return nil, nil, nil
}
runIdsReq := &crossmessage.GetLatestRunIDsRequest{
ConversationID: *convID,
AppID: resolvedAppID,
UserID: userID,
Rounds: historyRounds + 1,
SectionID: *sectionID,
}
runIds, err := crossmessage.DefaultSVC().GetLatestRunIDs(ctx, runIdsReq)
if err != nil {
logs.CtxErrorf(ctx, "failed to get latest run ids: %v", err)
return nil, nil, nil
}
if len(runIds) <= 1 {
return []*crossmessage.WfMessage{}, []*schema.Message{}, nil
}
runIds = runIds[1:]
response, err := crossmessage.DefaultSVC().GetMessagesByRunIDs(ctx, &crossmessage.GetMessagesByRunIDsRequest{
ConversationID: *convID,
RunIDs: runIds,
})
if err != nil {
logs.CtxErrorf(ctx, "failed to get messages by run ids: %v", err)
return nil, nil, nil
}
return response.Messages, response.SchemaMessages, nil
}

View File

@@ -20,13 +20,14 @@ import (
"context"
"errors"
"fmt"
"strconv"
"github.com/spf13/cast"
"golang.org/x/exp/maps"
"golang.org/x/sync/errgroup"
"gorm.io/gorm"
"strconv"
einoCompose "github.com/cloudwego/eino/compose"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
@@ -38,6 +39,7 @@ import (
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/adaptor"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/intentdetector"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/knowledge"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/llm"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
@@ -45,6 +47,7 @@ import (
"github.com/coze-dev/coze-studio/backend/infra/contract/chatmodel"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
@@ -56,6 +59,7 @@ type impl struct {
repo workflow.Repository
*asToolImpl
*executableImpl
*conversationImpl
}
func NewWorkflowService(repo workflow.Repository) workflow.Service {
@@ -67,12 +71,14 @@ func NewWorkflowService(repo workflow.Repository) workflow.Service {
executableImpl: &executableImpl{
repo: repo,
},
conversationImpl: &conversationImpl{repo: repo},
}
}
func NewWorkflowRepository(idgen idgen.IDGenerator, db *gorm.DB, redis cache.Cmdable, tos storage.Storage,
cpStore einoCompose.CheckPointStore, chatModel chatmodel.BaseChatModel, workflowConfig workflow.WorkflowConfig) workflow.Repository {
return repo.NewRepository(idgen, db, redis, tos, cpStore, chatModel, workflowConfig)
cpStore einoCompose.CheckPointStore, chatModel chatmodel.BaseChatModel, cfg workflow.WorkflowConfig) (workflow.Repository, error) {
return repo.NewRepository(idgen, db, redis, tos, cpStore, chatModel, cfg)
}
func (i *impl) ListNodeMeta(_ context.Context, nodeTypes map[entity.NodeType]bool) (map[string][]*entity.NodeTypeMeta, []entity.Category, error) {
@@ -440,10 +446,13 @@ func (i *impl) collectNodePropertyMap(ctx context.Context, canvas *vo.Canvas) (m
var canvasSchema string
if n.Data.Inputs.WorkflowVersion != "" {
versionInfo, err := i.repo.GetVersion(ctx, wid, n.Data.Inputs.WorkflowVersion)
versionInfo, existed, err := i.repo.GetVersion(ctx, wid, n.Data.Inputs.WorkflowVersion)
if err != nil {
return nil, err
}
if !existed {
return nil, vo.WrapError(errno.ErrWorkflowNotFound, fmt.Errorf("workflow version %s not found for ID %d: %w", n.Data.Inputs.WorkflowVersion, wid, err), errorx.KV("id", strconv.FormatInt(wid, 10)))
}
canvasSchema = versionInfo.Canvas
} else {
draftInfo, err := i.repo.DraftV2(ctx, wid, "")
@@ -522,6 +531,9 @@ func isEnableChatHistory(s *schema.NodeSchema) bool {
case entity.NodeTypeIntentDetector:
llmParam := s.Configs.(*intentdetector.Config).LLMParams
return llmParam.EnableChatHistory
case entity.NodeTypeKnowledgeRetriever:
chatParam := s.Configs.(*knowledge.RetrieveConfig).ChatHistorySetting
return chatParam != nil && chatParam.EnableChatHistory
default:
return false
}
@@ -541,6 +553,103 @@ func isRefGlobalVariable(s *schema.NodeSchema) bool {
return false
}
func (i *impl) CreateChatFlowRole(ctx context.Context, role *vo.ChatFlowRoleCreate) (int64, error) {
id, err := i.repo.CreateChatFlowRoleConfig(ctx, &entity.ChatFlowRole{
Name: role.Name,
Description: role.Description,
WorkflowID: role.WorkflowID,
CreatorID: role.CreatorID,
AudioConfig: role.AudioConfig,
UserInputConfig: role.UserInputConfig,
AvatarUri: role.AvatarUri,
BackgroundImageInfo: role.BackgroundImageInfo,
OnboardingInfo: role.OnboardingInfo,
SuggestReplyInfo: role.SuggestReplyInfo,
})
if err != nil {
return 0, err
}
return id, nil
}
func (i *impl) UpdateChatFlowRole(ctx context.Context, workflowID int64, role *vo.ChatFlowRoleUpdate) error {
err := i.repo.UpdateChatFlowRoleConfig(ctx, workflowID, role)
if err != nil {
return err
}
return nil
}
func (i *impl) GetChatFlowRole(ctx context.Context, workflowID int64, version string) (*entity.ChatFlowRole, error) {
role, err, isExist := i.repo.GetChatFlowRoleConfig(ctx, workflowID, version)
if !isExist {
logs.CtxWarnf(ctx, "chat flow role not exist, workflow id %v, version %v", workflowID, version)
// Return (nil, nil) on 'NotExist' to align with the production behavior,
// where the GET API may be called before the CREATE API during chatflow creation.
return nil, nil
}
if err != nil {
return nil, err
}
return role, nil
}
func (i *impl) GetWorkflowVersionsByConnector(ctx context.Context, connectorID, workflowID int64, limit int) ([]string, error) {
return i.repo.GetVersionListByConnectorAndWorkflowID(ctx, connectorID, workflowID, limit)
}
func (i *impl) DeleteChatFlowRole(ctx context.Context, id int64, workflowID int64) error {
return i.repo.DeleteChatFlowRoleConfig(ctx, id, workflowID)
}
func (i *impl) PublishChatFlowRole(ctx context.Context, policy *vo.PublishRolePolicy) error {
if policy.WorkflowID == 0 || policy.CreatorID == 0 || policy.Version == "" {
logs.CtxErrorf(ctx, "invalid publish role policy, workflow id %v, creator id %v should not be zero, version %v should not be empty", policy.WorkflowID, policy.CreatorID, policy.Version)
return vo.WrapError(errno.ErrInvalidParameter, fmt.Errorf("invalid publish role policy, workflow id %v, creator id %v should not be zero, version %v should not be empty", policy.WorkflowID, policy.CreatorID, policy.Version))
}
wf, err := i.repo.GetEntity(ctx, &vo.GetPolicy{
ID: policy.WorkflowID,
MetaOnly: true,
})
if err != nil {
return err
}
if wf.Mode != cloudworkflow.WorkflowMode_ChatFlow {
return vo.WrapError(errno.ErrChatFlowRoleOperationFail, fmt.Errorf("workflow id %v, mode %v is not a chatflow", policy.WorkflowID, wf.Mode))
}
role, err, isExist := i.repo.GetChatFlowRoleConfig(ctx, policy.WorkflowID, "")
if !isExist {
logs.CtxErrorf(ctx, "get draft chat flow role nil, workflow id %v", policy.WorkflowID)
return vo.WrapError(errno.ErrChatFlowRoleOperationFail, fmt.Errorf("get draft chat flow role nil, workflow id %v", policy.WorkflowID))
}
if err != nil {
return vo.WrapIfNeeded(errno.ErrChatFlowRoleOperationFail, err)
}
_, err = i.repo.CreateChatFlowRoleConfig(ctx, &entity.ChatFlowRole{
Name: role.Name,
Description: role.Description,
WorkflowID: policy.WorkflowID,
CreatorID: policy.CreatorID,
AudioConfig: role.AudioConfig,
UserInputConfig: role.UserInputConfig,
AvatarUri: role.AvatarUri,
BackgroundImageInfo: role.BackgroundImageInfo,
OnboardingInfo: role.OnboardingInfo,
SuggestReplyInfo: role.SuggestReplyInfo,
Version: policy.Version,
})
if err != nil {
return err
}
return nil
}
func canvasToRefs(referringID int64, canvasStr string) (map[entity.WorkflowReferenceKey]struct{}, error) {
var canvas vo.Canvas
if err := sonic.UnmarshalString(canvasStr, &canvas); err != nil {
@@ -659,6 +768,13 @@ func (i *impl) UpdateMeta(ctx context.Context, id int64, metaUpdate *vo.MetaUpda
return err
}
if metaUpdate.WorkflowMode != nil && *metaUpdate.WorkflowMode == cloudworkflow.WorkflowMode_ChatFlow {
err = i.adaptToChatFlow(ctx, id)
if err != nil {
return err
}
}
return nil
}
@@ -667,6 +783,35 @@ func (i *impl) CopyWorkflow(ctx context.Context, workflowID int64, policy vo.Cop
if err != nil {
return nil, err
}
// chat flow should copy role config
if wf.Mode == cloudworkflow.WorkflowMode_ChatFlow {
role, err, isExist := i.repo.GetChatFlowRoleConfig(ctx, workflowID, "")
if !isExist {
logs.CtxErrorf(ctx, "get draft chat flow role nil, workflow id %v", workflowID)
return nil, vo.WrapError(errno.ErrChatFlowRoleOperationFail, fmt.Errorf("get draft chat flow role nil, workflow id %v", workflowID))
}
if err != nil {
return nil, vo.WrapIfNeeded(errno.ErrChatFlowRoleOperationFail, err)
}
_, err = i.repo.CreateChatFlowRoleConfig(ctx, &entity.ChatFlowRole{
Name: role.Name,
Description: role.Description,
WorkflowID: wf.ID,
CreatorID: wf.CreatorID,
AudioConfig: role.AudioConfig,
UserInputConfig: role.UserInputConfig,
AvatarUri: role.AvatarUri,
BackgroundImageInfo: role.BackgroundImageInfo,
OnboardingInfo: role.OnboardingInfo,
SuggestReplyInfo: role.SuggestReplyInfo,
})
if err != nil {
return nil, err
}
}
return wf, nil
@@ -677,7 +822,7 @@ func (i *impl) ReleaseApplicationWorkflows(ctx context.Context, appID int64, con
return nil, fmt.Errorf("connector ids is required")
}
wfs, _, err := i.MGet(ctx, &vo.MGetPolicy{
allWorkflowsInApp, _, err := i.MGet(ctx, &vo.MGetPolicy{
MetaQuery: vo.MetaQuery{
AppID: &appID,
},
@@ -688,14 +833,15 @@ func (i *impl) ReleaseApplicationWorkflows(ctx context.Context, appID int64, con
}
relatedPlugins := make(map[int64]*plugin.PluginEntity, len(config.PluginIDs))
relatedWorkflow := make(map[int64]entity.IDVersionPair, len(wfs))
relatedWorkflow := make(map[int64]entity.IDVersionPair, len(allWorkflowsInApp))
for _, wf := range wfs {
for _, wf := range allWorkflowsInApp {
relatedWorkflow[wf.ID] = entity.IDVersionPair{
ID: wf.ID,
Version: config.Version,
}
}
for _, id := range config.PluginIDs {
relatedPlugins[id] = &plugin.PluginEntity{
PluginID: id,
@@ -704,7 +850,22 @@ func (i *impl) ReleaseApplicationWorkflows(ctx context.Context, appID int64, con
}
vIssues := make([]*vo.ValidateIssue, 0)
for _, wf := range wfs {
willPublishWorkflows := make([]*entity.Workflow, 0)
if len(config.WorkflowIDs) == 0 {
willPublishWorkflows = allWorkflowsInApp
} else {
willPublishWorkflows, _, err = i.MGet(ctx, &vo.MGetPolicy{
MetaQuery: vo.MetaQuery{
AppID: &appID,
IDs: config.WorkflowIDs,
},
QType: workflowModel.FromDraft,
})
}
for _, wf := range willPublishWorkflows {
issues, err := validateWorkflowTree(ctx, vo.ValidateTreeConfig{
CanvasSchema: wf.Canvas,
AppID: ptr.Of(appID),
@@ -723,7 +884,7 @@ func (i *impl) ReleaseApplicationWorkflows(ctx context.Context, appID int64, con
return vIssues, nil
}
for _, wf := range wfs {
for _, wf := range willPublishWorkflows {
c := &vo.Canvas{}
err := sonic.UnmarshalString(wf.Canvas, c)
if err != nil {
@@ -747,9 +908,8 @@ func (i *impl) ReleaseApplicationWorkflows(ctx context.Context, appID int64, con
}
userID := ctxutil.MustGetUIDFromCtx(ctx)
workflowsToPublish := make(map[int64]*vo.VersionInfo)
for _, wf := range wfs {
for _, wf := range willPublishWorkflows {
inputStr, err := sonic.MarshalString(wf.InputParams)
if err != nil {
return nil, err
@@ -774,8 +934,16 @@ func (i *impl) ReleaseApplicationWorkflows(ctx context.Context, appID int64, con
}
}
workflowIDs := make([]int64, 0, len(wfs))
workflowIDs := make([]int64, 0, len(willPublishWorkflows))
for id, vInfo := range workflowsToPublish {
// if version existed skip
_, existed, err := i.repo.GetVersion(ctx, id, config.Version)
if err != nil {
return nil, err
}
if existed {
continue
}
wfRefs, err := canvasToRefs(id, vInfo.Canvas)
if err != nil {
return nil, err
@@ -787,6 +955,24 @@ func (i *impl) ReleaseApplicationWorkflows(ctx context.Context, appID int64, con
}
}
err = i.ReleaseConversationTemplate(ctx, appID, config.Version)
if err != nil {
return nil, err
}
for _, wf := range willPublishWorkflows {
if wf.Mode == cloudworkflow.WorkflowMode_ChatFlow {
err = i.PublishChatFlowRole(ctx, &vo.PublishRolePolicy{
WorkflowID: wf.ID,
CreatorID: wf.CreatorID,
Version: config.Version,
})
if err != nil {
return nil, err
}
}
}
for _, connectorID := range config.ConnectorIDs {
err = i.repo.BatchCreateConnectorWorkflowVersion(ctx, appID, connectorID, workflowIDs, config.Version)
if err != nil {
@@ -889,7 +1075,7 @@ func (i *impl) CopyWorkflowFromAppToLibrary(ctx context.Context, workflowID int6
}
if node.Type == entity.NodeTypeLLM.IDStr() {
if node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.WorkflowFCParam != nil {
if node.Data.Inputs.LLM != nil && node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.WorkflowFCParam != nil {
for _, w := range node.Data.Inputs.FCParam.WorkflowFCParam.WorkflowList {
var (
v *vo.DraftInfo
@@ -1012,7 +1198,7 @@ func (i *impl) CopyWorkflowFromAppToLibrary(ctx context.Context, workflowID int6
return err
}
cwf, err := i.repo.CopyWorkflow(ctx, wf.id, vo.CopyWorkflowPolicy{
cwf, err := i.CopyWorkflow(ctx, wf.id, vo.CopyWorkflowPolicy{
TargetAppID: ptr.Of(int64(0)),
ModifiedCanvasSchema: ptr.Of(modifiedCanvasString),
})
@@ -1120,7 +1306,7 @@ func (i *impl) DuplicateWorkflowsByAppID(ctx context.Context, sourceAppID, targe
}
if node.Type == entity.NodeTypeLLM.IDStr() {
if node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.WorkflowFCParam != nil {
if node.Data.Inputs.LLM != nil && node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.WorkflowFCParam != nil {
for _, w := range node.Data.Inputs.FCParam.WorkflowFCParam.WorkflowList {
var (
v *vo.DraftInfo
@@ -1246,6 +1432,11 @@ func (i *impl) DuplicateWorkflowsByAppID(ctx context.Context, sourceAppID, targe
}
}
err = i.repo.CopyTemplateConversationByAppID(ctx, sourceAppID, targetAppID)
if err != nil {
return nil, err
}
return copiedWorkflowArray, nil
}
@@ -1368,7 +1559,7 @@ func (i *impl) GetWorkflowDependenceResource(ctx context.Context, workflowID int
ds.DatabaseIDs = append(ds.DatabaseIDs, dsID)
}
case entity.NodeTypeLLM:
if node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.PluginFCParam != nil {
if node.Data.Inputs.LLM != nil && node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.PluginFCParam != nil {
for idx := range node.Data.Inputs.FCParam.PluginFCParam.PluginList {
if node.Data.Inputs.FCParam.PluginFCParam.PluginList[idx].IsDraft {
pl := node.Data.Inputs.FCParam.PluginFCParam.PluginList[idx]
@@ -1382,7 +1573,7 @@ func (i *impl) GetWorkflowDependenceResource(ctx context.Context, workflowID int
}
}
if node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.KnowledgeFCParam != nil {
if node.Data.Inputs.LLM != nil && node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.KnowledgeFCParam != nil {
for idx := range node.Data.Inputs.FCParam.KnowledgeFCParam.KnowledgeList {
kn := node.Data.Inputs.FCParam.KnowledgeFCParam.KnowledgeList[idx]
kid, err := strconv.ParseInt(kn.ID, 10, 64)
@@ -1394,7 +1585,7 @@ func (i *impl) GetWorkflowDependenceResource(ctx context.Context, workflowID int
}
}
if node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.WorkflowFCParam != nil {
if node.Data.Inputs.LLM != nil && node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.WorkflowFCParam != nil {
for idx := range node.Data.Inputs.FCParam.WorkflowFCParam.WorkflowList {
if node.Data.Inputs.FCParam.WorkflowFCParam.WorkflowList[idx].IsDraft {
wID, err := strconv.ParseInt(node.Data.Inputs.FCParam.WorkflowFCParam.WorkflowList[idx].WorkflowID, 10, 64)
@@ -1467,6 +1658,165 @@ func (i *impl) GetWorkflowDependenceResource(ctx context.Context, workflowID int
}
func (i *impl) checkBotAgentNode(node *vo.Node) error {
if node.Type == entity.NodeTypeCreateConversation.IDStr() || node.Type == entity.NodeTypeConversationDelete.IDStr() || node.Type == entity.NodeTypeConversationUpdate.IDStr() || node.Type == entity.NodeTypeConversationList.IDStr() {
return errors.New("conversation-related nodes are not supported in chatflow")
}
return nil
}
func (i *impl) validateNodesRecursively(ctx context.Context, nodes []*vo.Node, checkType cloudworkflow.CheckType, visited map[string]struct{}, repo workflow.Repository) error {
queue := make([]*vo.Node, 0, len(nodes))
queue = append(queue, nodes...)
for len(queue) > 0 {
node := queue[0]
queue = queue[1:]
if node == nil {
continue
}
var checkErr error
switch checkType {
case cloudworkflow.CheckType_BotAgent:
checkErr = i.checkBotAgentNode(node)
default:
// For now, we only handle BotAgent check, so we can do nothing here.
// In the future, if there are other check types that need to be validated on every node, this logic will need to be adjusted.
}
if checkErr != nil {
return checkErr
}
// Enqueue nested nodes for BFS traversal. This handles Loop, Batch, and other nodes with nested blocks.
if len(node.Blocks) > 0 {
queue = append(queue, node.Blocks...)
}
if node.Type == entity.NodeTypeSubWorkflow.IDStr() && node.Data != nil && node.Data.Inputs != nil {
workflowIDStr := node.Data.Inputs.WorkflowID
if workflowIDStr == "" {
continue
}
workflowID, err := strconv.ParseInt(workflowIDStr, 10, 64)
if err != nil {
return fmt.Errorf("invalid workflow ID in sub-workflow node %s: %w", node.ID, err)
}
version := node.Data.Inputs.WorkflowVersion
qType := workflowModel.FromDraft
if version != "" {
qType = workflowModel.FromSpecificVersion
}
visitedKey := fmt.Sprintf("%d:%s", workflowID, version)
if _, ok := visited[visitedKey]; ok {
continue
}
visited[visitedKey] = struct{}{}
subWfEntity, err := repo.GetEntity(ctx, &vo.GetPolicy{
ID: workflowID,
QType: qType,
Version: version,
})
if err != nil {
delete(visited, visitedKey)
if errors.Is(err, gorm.ErrRecordNotFound) {
continue
}
return fmt.Errorf("failed to get sub-workflow entity %d: %w", workflowID, err)
}
var canvas vo.Canvas
if err := sonic.UnmarshalString(subWfEntity.Canvas, &canvas); err != nil {
return fmt.Errorf("failed to unmarshal canvas for workflow %d: %w", subWfEntity.ID, err)
}
queue = append(queue, canvas.Nodes...)
}
if node.Type == entity.NodeTypeLLM.IDStr() && node.Data != nil && node.Data.Inputs != nil && node.Data.Inputs.LLM != nil && node.Data.Inputs.FCParam != nil && node.Data.Inputs.FCParam.WorkflowFCParam != nil {
for _, subWfInfo := range node.Data.Inputs.FCParam.WorkflowFCParam.WorkflowList {
if subWfInfo.WorkflowID == "" {
continue
}
workflowID, err := strconv.ParseInt(subWfInfo.WorkflowID, 10, 64)
if err != nil {
return fmt.Errorf("invalid workflow ID in large model node %s: %w", node.ID, err)
}
version := subWfInfo.WorkflowVersion
qType := workflowModel.FromDraft
if version != "" {
qType = workflowModel.FromSpecificVersion
}
visitedKey := fmt.Sprintf("%d:%s", workflowID, version)
if _, ok := visited[visitedKey]; ok {
continue
}
visited[visitedKey] = struct{}{}
subWfEntity, err := repo.GetEntity(ctx, &vo.GetPolicy{
ID: workflowID,
QType: qType,
Version: version,
})
if err != nil {
delete(visited, visitedKey)
if errors.Is(err, gorm.ErrRecordNotFound) {
continue
}
return fmt.Errorf("failed to get sub-workflow entity %d from large model node: %w", workflowID, err)
}
var canvas vo.Canvas
if err := sonic.UnmarshalString(subWfEntity.Canvas, &canvas); err != nil {
return fmt.Errorf("failed to unmarshal canvas for workflow %d from large model node: %w", subWfEntity.ID, err)
}
queue = append(queue, canvas.Nodes...)
}
}
}
return nil
}
func (i *impl) WorkflowSchemaCheck(ctx context.Context, wf *entity.Workflow, checks []cloudworkflow.CheckType) ([]*cloudworkflow.CheckResult, error) {
checkResults := make([]*cloudworkflow.CheckResult, 0, len(checks))
var canvas vo.Canvas
if err := sonic.UnmarshalString(wf.Canvas, &canvas); err != nil {
return nil, fmt.Errorf("failed to unmarshal canvas for workflow %d: %w", wf.ID, err)
}
for _, checkType := range checks {
visited := make(map[string]struct{})
visitedKey := fmt.Sprintf("%d:%s", wf.ID, wf.GetVersion())
visited[visitedKey] = struct{}{}
err := i.validateNodesRecursively(ctx, canvas.Nodes, checkType, visited, i.repo)
if err != nil {
checkResults = append(checkResults, &cloudworkflow.CheckResult{
IsPass: false,
Reason: err.Error(),
Type: checkType,
})
} else {
checkResults = append(checkResults, &cloudworkflow.CheckResult{
IsPass: true,
Type: checkType,
Reason: "",
})
}
}
return checkResults, nil
}
func (i *impl) MGet(ctx context.Context, policy *vo.MGetPolicy) ([]*entity.Workflow, int64, error) {
if policy.MetaOnly {
metas, total, err := i.repo.MGetMetas(ctx, &policy.MetaQuery)
@@ -1527,11 +1877,13 @@ func (i *impl) MGet(ctx context.Context, policy *vo.MGetPolicy) ([]*entity.Workf
index := 0
for id, version := range policy.Versions {
v, err := i.repo.GetVersion(ctx, id, version)
v, existed, err := i.repo.GetVersion(ctx, id, version)
if err != nil {
return nil, total, err
}
if !existed {
return nil, total, vo.WrapError(errno.ErrWorkflowNotFound, fmt.Errorf("workflow version %s not found for ID %d: %w", version, id, err), errorx.KV("id", strconv.FormatInt(id, 10)))
}
inputs, outputs, err := ioF(v.InputParamsStr, v.OutputParamsStr)
if err != nil {
return nil, total, err
@@ -1562,6 +1914,14 @@ func (i *impl) MGet(ctx context.Context, policy *vo.MGetPolicy) ([]*entity.Workf
}
}
func (i *impl) BindConvRelatedInfo(ctx context.Context, convID int64, info entity.ConvRelatedInfo) error {
return i.repo.BindConvRelatedInfo(ctx, convID, info)
}
func (i *impl) GetConvRelatedInfo(ctx context.Context, convID int64) (*entity.ConvRelatedInfo, bool, func() error, error) {
return i.repo.GetConvRelatedInfo(ctx, convID)
}
func (i *impl) calculateTestRunSuccess(ctx context.Context, c *vo.Canvas, wid int64) (bool, error) {
sc, err := adaptor.CanvasToWorkflowSchema(ctx, c)
if err != nil { // not even legal, test run can't possibly be successful
@@ -1766,3 +2126,58 @@ func replaceRelatedWorkflowOrExternalResourceInWorkflowNodes(nodes []*vo.Node, r
func RegisterAllNodeAdaptors() {
adaptor.RegisterAllNodeAdaptors()
}
func (i *impl) adaptToChatFlow(ctx context.Context, wID int64) error {
wfEntity, err := i.repo.GetEntity(ctx, &vo.GetPolicy{
ID: wID,
QType: workflowModel.FromDraft,
})
if err != nil {
return err
}
canvas := &vo.Canvas{}
err = sonic.UnmarshalString(wfEntity.Canvas, canvas)
if err != nil {
return err
}
var startNode *vo.Node
for _, node := range canvas.Nodes {
if node.Type == entity.NodeTypeEntry.IDStr() {
startNode = node
break
}
}
if startNode == nil {
return fmt.Errorf("can not find start node")
}
vMap := make(map[string]bool)
for _, o := range startNode.Data.Outputs {
v, err := vo.ParseVariable(o)
if err != nil {
return err
}
vMap[v.Name] = true
}
if _, ok := vMap["USER_INPUT"]; !ok {
startNode.Data.Outputs = append(startNode.Data.Outputs, &vo.Variable{
Name: "USER_INPUT",
Type: vo.VariableTypeString,
})
}
if _, ok := vMap["CONVERSATION_NAME"]; !ok {
startNode.Data.Outputs = append(startNode.Data.Outputs, &vo.Variable{
Name: "CONVERSATION_NAME",
Type: vo.VariableTypeString,
DefaultValue: "Default",
})
}
canvasStr, err := sonic.MarshalString(canvas)
if err != nil {
return err
}
return i.Save(ctx, wID, canvasStr)
}

View File

@@ -22,11 +22,15 @@ import (
"strconv"
"strings"
cloudworkflow "github.com/coze-dev/coze-studio/backend/api/model/workflow"
workflowModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/workflow"
"github.com/coze-dev/coze-studio/backend/api/model/workflow"
wf "github.com/coze-dev/coze-studio/backend/domain/workflow"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/adaptor"
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/validate"
"github.com/coze-dev/coze-studio/backend/domain/workflow/variable"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
@@ -102,17 +106,17 @@ func validateWorkflowTree(ctx context.Context, config vo.ValidateTreeConfig) ([]
return issues, nil
}
func convertToValidationError(issue *validate.Issue) *cloudworkflow.ValidateErrorData {
e := &cloudworkflow.ValidateErrorData{}
func convertToValidationError(issue *validate.Issue) *workflow.ValidateErrorData {
e := &workflow.ValidateErrorData{}
e.Message = issue.Message
if issue.NodeErr != nil {
e.Type = cloudworkflow.ValidateErrorType_BotValidateNodeErr
e.NodeError = &cloudworkflow.NodeError{
e.Type = workflow.ValidateErrorType_BotValidateNodeErr
e.NodeError = &workflow.NodeError{
NodeID: issue.NodeErr.NodeID,
}
} else if issue.PathErr != nil {
e.Type = cloudworkflow.ValidateErrorType_BotValidatePathErr
e.PathError = &cloudworkflow.PathError{
e.Type = workflow.ValidateErrorType_BotValidatePathErr
e.PathError = &workflow.PathError{
Start: issue.PathErr.StartNode,
End: issue.PathErr.EndNode,
}
@@ -121,8 +125,8 @@ func convertToValidationError(issue *validate.Issue) *cloudworkflow.ValidateErro
return e
}
func toValidateErrorData(issues []*validate.Issue) []*cloudworkflow.ValidateErrorData {
validateErrors := make([]*cloudworkflow.ValidateErrorData, 0, len(issues))
func toValidateErrorData(issues []*validate.Issue) []*workflow.ValidateErrorData {
validateErrors := make([]*workflow.ValidateErrorData, 0, len(issues))
for _, issue := range issues {
validateErrors = append(validateErrors, convertToValidationError(issue))
}
@@ -197,3 +201,214 @@ func isIncremental(prev version, next version) bool {
return next.Patch > prev.Patch
}
func getMaxHistoryRoundsRecursively(ctx context.Context, wfEntity *entity.Workflow, repo wf.Repository) (int64, error) {
visited := make(map[string]struct{})
maxRounds := int64(0)
err := getMaxHistoryRoundsRecursiveHelper(ctx, wfEntity, repo, visited, &maxRounds)
return maxRounds, err
}
func getMaxHistoryRoundsRecursiveHelper(ctx context.Context, wfEntity *entity.Workflow, repo wf.Repository, visited map[string]struct{}, maxRounds *int64) error {
visitedKey := fmt.Sprintf("%d:%s", wfEntity.ID, wfEntity.GetVersion())
if _, ok := visited[visitedKey]; ok {
return nil
}
visited[visitedKey] = struct{}{}
var canvas vo.Canvas
if err := sonic.UnmarshalString(wfEntity.Canvas, &canvas); err != nil {
return fmt.Errorf("failed to unmarshal canvas for workflow %d: %w", wfEntity.ID, err)
}
return collectMaxHistoryRounds(ctx, canvas.Nodes, repo, visited, maxRounds)
}
func collectMaxHistoryRounds(ctx context.Context, nodes []*vo.Node, repo wf.Repository, visited map[string]struct{}, maxRounds *int64) error {
for _, node := range nodes {
if node == nil {
continue
}
if node.Data != nil && node.Data.Inputs != nil && node.Data.Inputs.ChatHistorySetting != nil && node.Data.Inputs.ChatHistorySetting.EnableChatHistory {
if node.Data.Inputs.ChatHistorySetting.ChatHistoryRound > *maxRounds {
*maxRounds = node.Data.Inputs.ChatHistorySetting.ChatHistoryRound
}
} else if node.Type == entity.NodeTypeLLM.IDStr() && node.Data != nil && node.Data.Inputs != nil && node.Data.Inputs.LLMParam != nil {
param := node.Data.Inputs.LLMParam
bs, _ := sonic.Marshal(param)
llmParam := make(vo.LLMParam, 0)
if err := sonic.Unmarshal(bs, &llmParam); err != nil {
return err
}
var chatHistoryEnabled bool
var chatHistoryRound int64
for _, param := range llmParam {
switch param.Name {
case "enableChatHistory":
if val, ok := param.Input.Value.Content.(bool); ok {
b := val
chatHistoryEnabled = b
}
case "chatHistoryRound":
if strVal, ok := param.Input.Value.Content.(string); ok {
int64Val, err := strconv.ParseInt(strVal, 10, 64)
if err != nil {
return err
}
chatHistoryRound = int64Val
}
}
}
if chatHistoryEnabled {
if chatHistoryRound > *maxRounds {
*maxRounds = chatHistoryRound
}
}
}
isSubWorkflow := node.Type == entity.NodeTypeSubWorkflow.IDStr() && node.Data != nil && node.Data.Inputs != nil
if isSubWorkflow {
workflowIDStr := node.Data.Inputs.WorkflowID
if workflowIDStr == "" {
continue
}
workflowID, err := strconv.ParseInt(workflowIDStr, 10, 64)
if err != nil {
return fmt.Errorf("invalid workflow ID in sub-workflow node %s: %w", node.ID, err)
}
subWfEntity, err := repo.GetEntity(ctx, &vo.GetPolicy{
ID: workflowID,
QType: ternary.IFElse(len(node.Data.Inputs.WorkflowVersion) == 0, workflowModel.FromDraft, workflowModel.FromSpecificVersion),
Version: node.Data.Inputs.WorkflowVersion,
})
if err != nil {
return fmt.Errorf("failed to get sub-workflow entity %d: %w", workflowID, err)
}
if err := getMaxHistoryRoundsRecursiveHelper(ctx, subWfEntity, repo, visited, maxRounds); err != nil {
return err
}
}
if len(node.Blocks) > 0 {
if err := collectMaxHistoryRounds(ctx, node.Blocks, repo, visited, maxRounds); err != nil {
return err
}
}
}
return nil
}
func getHistoryRoundsFromNode(ctx context.Context, wfEntity *entity.Workflow, nodeID string, repo wf.Repository) (int64, error) {
if wfEntity == nil {
return 0, nil
}
visited := make(map[string]struct{})
visitedKey := fmt.Sprintf("%d:%s", wfEntity.ID, wfEntity.GetVersion())
if _, ok := visited[visitedKey]; ok {
return 0, nil
}
visited[visitedKey] = struct{}{}
maxRounds := int64(0)
c := &vo.Canvas{}
if err := sonic.UnmarshalString(wfEntity.Canvas, c); err != nil {
return 0, fmt.Errorf("failed to unmarshal canvas: %w", err)
}
var (
n *vo.Node
nodeFinder func(nodes []*vo.Node) *vo.Node
)
nodeFinder = func(nodes []*vo.Node) *vo.Node {
for i := range nodes {
if nodes[i].ID == nodeID {
return nodes[i]
}
if len(nodes[i].Blocks) > 0 {
if n := nodeFinder(nodes[i].Blocks); n != nil {
return n
}
}
}
return nil
}
n = nodeFinder(c.Nodes)
if n.Type == entity.NodeTypeLLM.IDStr() {
if n.Data == nil || n.Data.Inputs == nil {
return 0, nil
}
param := n.Data.Inputs.LLMParam
bs, _ := sonic.Marshal(param)
llmParam := make(vo.LLMParam, 0)
if err := sonic.Unmarshal(bs, &llmParam); err != nil {
return 0, err
}
var chatHistoryEnabled bool
var chatHistoryRound int64
for _, param := range llmParam {
switch param.Name {
case "enableChatHistory":
if val, ok := param.Input.Value.Content.(bool); ok {
b := val
chatHistoryEnabled = b
}
case "chatHistoryRound":
if strVal, ok := param.Input.Value.Content.(string); ok {
int64Val, err := strconv.ParseInt(strVal, 10, 64)
if err != nil {
return 0, err
}
chatHistoryRound = int64Val
}
}
}
if chatHistoryEnabled {
return chatHistoryRound, nil
}
return 0, nil
}
if n.Type == entity.NodeTypeIntentDetector.IDStr() || n.Type == entity.NodeTypeKnowledgeRetriever.IDStr() {
if n.Data != nil && n.Data.Inputs != nil && n.Data.Inputs.ChatHistorySetting != nil && n.Data.Inputs.ChatHistorySetting.EnableChatHistory {
return n.Data.Inputs.ChatHistorySetting.ChatHistoryRound, nil
}
return 0, nil
}
if n.Type == entity.NodeTypeSubWorkflow.IDStr() {
if n.Data != nil && n.Data.Inputs != nil {
workflowIDStr := n.Data.Inputs.WorkflowID
if workflowIDStr == "" {
return 0, nil
}
workflowID, err := strconv.ParseInt(workflowIDStr, 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid workflow ID in sub-workflow node %s: %w", n.ID, err)
}
subWfEntity, err := repo.GetEntity(ctx, &vo.GetPolicy{
ID: workflowID,
QType: ternary.IFElse(len(n.Data.Inputs.WorkflowVersion) == 0, workflowModel.FromDraft, workflowModel.FromSpecificVersion),
Version: n.Data.Inputs.WorkflowVersion,
})
if err != nil {
return 0, fmt.Errorf("failed to get sub-workflow entity %d: %w", workflowID, err)
}
if err := getMaxHistoryRoundsRecursiveHelper(ctx, subWfEntity, repo, visited, &maxRounds); err != nil {
return 0, err
}
return maxRounds, nil
}
}
if len(n.Blocks) > 0 {
if err := collectMaxHistoryRounds(ctx, n.Blocks, repo, visited, &maxRounds); err != nil {
return 0, err
}
}
return maxRounds, nil
}