diff --git a/backend/api/handler/coze/workflow_service.go b/backend/api/handler/coze/workflow_service.go index 8529dc95d..009ab3169 100644 --- a/backend/api/handler/coze/workflow_service.go +++ b/backend/api/handler/coze/workflow_service.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" "io" + "strconv" "github.com/cloudwego/eino/schema" "github.com/cloudwego/hertz/pkg/app" @@ -1094,9 +1095,62 @@ func OpenAPIChatFlowRun(ctx context.Context, c *app.RequestContext) { return } - resp := new(workflow.ChatFlowRunResponse) + w := sse.NewWriter(c) + c.SetContentType("text/event-stream; charset=utf-8") + c.Response.Header.Set("Cache-Control", "no-cache") + c.Response.Header.Set("Connection", "keep-alive") + c.Response.Header.Set("Access-Control-Allow-Origin", "*") - c.JSON(consts.StatusOK, resp) + sr, err := appworkflow.SVC.OpenAPIChatFlowRun(ctx, &req) + if err != nil { + internalServerErrorResponse(ctx, c, err) + return + } + sendChatFlowStreamRunSSE(ctx, w, sr) + +} + +func sendChatFlowStreamRunSSE(ctx context.Context, w *sse.Writer, sr *schema.StreamReader[[]*workflow.ChatFlowRunResponse]) { + defer func() { + _ = w.Close() + sr.Close() + }() + seq := int64(1) + for { + respList, err := sr.Recv() + + if err != nil { + if errors.Is(err, io.EOF) { + // finish + break + } + + event := &sse.Event{ + Type: "error", + Data: []byte(err.Error()), + } + + if err = w.Write(event); err != nil { + logs.CtxErrorf(ctx, "publish stream event failed, err:%v", err) + } + return + } + + for _, resp := range respList { + event := &sse.Event{ + ID: strconv.FormatInt(seq, 10), + Type: resp.Event, + Data: []byte(resp.Data), + } + + if err = w.Write(event); err != nil { + logs.CtxErrorf(ctx, "publish stream event failed, err:%v", err) + return + } + seq++ + } + + } } // OpenAPIGetWorkflowInfo . @@ -1110,7 +1164,11 @@ func OpenAPIGetWorkflowInfo(ctx context.Context, c *app.RequestContext) { return } - resp := new(workflow.OpenAPIGetWorkflowInfoResponse) + resp, err := appworkflow.SVC.OpenAPIGetWorkflowInfo(ctx, &req) + if err != nil { + internalServerErrorResponse(ctx, c, err) + return + } c.JSON(consts.StatusOK, resp) } @@ -1154,3 +1212,22 @@ func GetExampleWorkFlowList(ctx context.Context, c *app.RequestContext) { c.JSON(consts.StatusOK, resp) } + +// OpenAPICreateConversation . +// @router /v1/workflow/conversation/create [POST] +func OpenAPICreateConversation(ctx context.Context, c *app.RequestContext) { + var err error + var req workflow.CreateConversationRequest + err = c.BindAndValidate(&req) + if err != nil { + c.String(consts.StatusBadRequest, err.Error()) + return + } + resp, err := appworkflow.SVC.OpenAPICreateConversation(ctx, &req) + if err != nil { + internalServerErrorResponse(ctx, c, err) + return + } + + c.JSON(consts.StatusOK, resp) +} diff --git a/backend/api/model/conversation/common/common.go b/backend/api/model/conversation/common/common.go index 5b48bdffe..74704c5e5 100644 --- a/backend/api/model/conversation/common/common.go +++ b/backend/api/model/conversation/common/common.go @@ -1,3 +1,19 @@ +/* + * Copyright 2025 coze-dev Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + // Code generated by thriftgo (0.4.1). DO NOT EDIT. package common @@ -52,6 +68,8 @@ func (p Scene) String() string { return "GenerateAgentInfo" case Scene_SceneOpenApi: return "SceneOpenApi" + case Scene_SceneWorkflow: + return "SceneWorkflow" } return "" } @@ -78,6 +96,8 @@ func SceneFromString(s string) (Scene, error) { return Scene_GenerateAgentInfo, nil case "SceneOpenApi": return Scene_SceneOpenApi, nil + case "SceneWorkflow": + return Scene_SceneWorkflow, nil } return Scene(0), fmt.Errorf("not a valid Scene string") } diff --git a/backend/api/model/workflow/workflow.go b/backend/api/model/workflow/workflow.go index 31b40d4c1..b824118d1 100644 --- a/backend/api/model/workflow/workflow.go +++ b/backend/api/model/workflow/workflow.go @@ -1,3 +1,19 @@ +/* + * Copyright 2025 coze-dev Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + // Code generated by thriftgo (0.4.1). DO NOT EDIT. package workflow @@ -78358,3 +78374,1403 @@ func (p *OpenAPIGetWorkflowInfoResponse) String() string { return fmt.Sprintf("OpenAPIGetWorkflowInfoResponse(%+v)", *p) } + +type CreateConversationRequest struct { + //自定义透传字段 + MetaData map[string]string `thrift:"MetaData,1,optional" form:"meta_data" json:"meta_data,omitempty"` + BotId *int64 `thrift:"BotId,3,optional" form:"bot_id" json:"bot_id,string,omitempty"` + ConnectorId *int64 `thrift:"ConnectorId,4,optional" form:"connector_id" json:"connector_id,string,omitempty"` + SpaceID *string `thrift:"SpaceID,5,optional" form:"space_id" json:"space_id,string,omitempty"` + AppID *string `thrift:"AppID,9,optional" json:"app_id" form:"AppID" query:"AppID"` + WorkflowID *string `thrift:"WorkflowID,10,optional" json:"workflow_id" form:"WorkflowID" query:"WorkflowID"` + ConversationMame *string `thrift:"ConversationMame,11,optional" json:"conversation_name" form:"ConversationMame" query:"ConversationMame"` + GetOrCreate *bool `thrift:"GetOrCreate,12,optional" json:"get_or_create" form:"GetOrCreate" query:"GetOrCreate"` + DraftMode *bool `thrift:"DraftMode,13,optional" json:"draft_mode" form:"DraftMode" query:"DraftMode"` + Base *base.Base `thrift:"Base,255,optional" form:"Base" json:"Base,omitempty" query:"Base"` +} + +func NewCreateConversationRequest() *CreateConversationRequest { + return &CreateConversationRequest{} +} + +func (p *CreateConversationRequest) InitDefault() { +} + +var CreateConversationRequest_MetaData_DEFAULT map[string]string + +func (p *CreateConversationRequest) GetMetaData() (v map[string]string) { + if !p.IsSetMetaData() { + return CreateConversationRequest_MetaData_DEFAULT + } + return p.MetaData +} + +var CreateConversationRequest_BotId_DEFAULT int64 + +func (p *CreateConversationRequest) GetBotId() (v int64) { + if !p.IsSetBotId() { + return CreateConversationRequest_BotId_DEFAULT + } + return *p.BotId +} + +var CreateConversationRequest_ConnectorId_DEFAULT int64 + +func (p *CreateConversationRequest) GetConnectorId() (v int64) { + if !p.IsSetConnectorId() { + return CreateConversationRequest_ConnectorId_DEFAULT + } + return *p.ConnectorId +} + +var CreateConversationRequest_SpaceID_DEFAULT string + +func (p *CreateConversationRequest) GetSpaceID() (v string) { + if !p.IsSetSpaceID() { + return CreateConversationRequest_SpaceID_DEFAULT + } + return *p.SpaceID +} + +var CreateConversationRequest_AppID_DEFAULT string + +func (p *CreateConversationRequest) GetAppID() (v string) { + if !p.IsSetAppID() { + return CreateConversationRequest_AppID_DEFAULT + } + return *p.AppID +} + +var CreateConversationRequest_WorkflowID_DEFAULT string + +func (p *CreateConversationRequest) GetWorkflowID() (v string) { + if !p.IsSetWorkflowID() { + return CreateConversationRequest_WorkflowID_DEFAULT + } + return *p.WorkflowID +} + +var CreateConversationRequest_ConversationMame_DEFAULT string + +func (p *CreateConversationRequest) GetConversationMame() (v string) { + if !p.IsSetConversationMame() { + return CreateConversationRequest_ConversationMame_DEFAULT + } + return *p.ConversationMame +} + +var CreateConversationRequest_GetOrCreate_DEFAULT bool + +func (p *CreateConversationRequest) GetGetOrCreate() (v bool) { + if !p.IsSetGetOrCreate() { + return CreateConversationRequest_GetOrCreate_DEFAULT + } + return *p.GetOrCreate +} + +var CreateConversationRequest_DraftMode_DEFAULT bool + +func (p *CreateConversationRequest) GetDraftMode() (v bool) { + if !p.IsSetDraftMode() { + return CreateConversationRequest_DraftMode_DEFAULT + } + return *p.DraftMode +} + +var CreateConversationRequest_Base_DEFAULT *base.Base + +func (p *CreateConversationRequest) GetBase() (v *base.Base) { + if !p.IsSetBase() { + return CreateConversationRequest_Base_DEFAULT + } + return p.Base +} + +var fieldIDToName_CreateConversationRequest = map[int16]string{ + 1: "MetaData", + 3: "BotId", + 4: "ConnectorId", + 5: "SpaceID", + 9: "AppID", + 10: "WorkflowID", + 11: "ConversationMame", + 12: "GetOrCreate", + 13: "DraftMode", + 255: "Base", +} + +func (p *CreateConversationRequest) IsSetMetaData() bool { + return p.MetaData != nil +} + +func (p *CreateConversationRequest) IsSetBotId() bool { + return p.BotId != nil +} + +func (p *CreateConversationRequest) IsSetConnectorId() bool { + return p.ConnectorId != nil +} + +func (p *CreateConversationRequest) IsSetSpaceID() bool { + return p.SpaceID != nil +} + +func (p *CreateConversationRequest) IsSetAppID() bool { + return p.AppID != nil +} + +func (p *CreateConversationRequest) IsSetWorkflowID() bool { + return p.WorkflowID != nil +} + +func (p *CreateConversationRequest) IsSetConversationMame() bool { + return p.ConversationMame != nil +} + +func (p *CreateConversationRequest) IsSetGetOrCreate() bool { + return p.GetOrCreate != nil +} + +func (p *CreateConversationRequest) IsSetDraftMode() bool { + return p.DraftMode != nil +} + +func (p *CreateConversationRequest) IsSetBase() bool { + return p.Base != nil +} + +func (p *CreateConversationRequest) Read(iprot thrift.TProtocol) (err error) { + var fieldTypeId thrift.TType + var fieldId int16 + + if _, err = iprot.ReadStructBegin(); err != nil { + goto ReadStructBeginError + } + + for { + _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() + if err != nil { + goto ReadFieldBeginError + } + if fieldTypeId == thrift.STOP { + break + } + + switch fieldId { + case 1: + if fieldTypeId == thrift.MAP { + if err = p.ReadField1(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 3: + if fieldTypeId == thrift.I64 { + if err = p.ReadField3(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 4: + if fieldTypeId == thrift.I64 { + if err = p.ReadField4(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 5: + if fieldTypeId == thrift.STRING { + if err = p.ReadField5(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 9: + if fieldTypeId == thrift.STRING { + if err = p.ReadField9(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 10: + if fieldTypeId == thrift.STRING { + if err = p.ReadField10(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 11: + if fieldTypeId == thrift.STRING { + if err = p.ReadField11(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 12: + if fieldTypeId == thrift.BOOL { + if err = p.ReadField12(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 13: + if fieldTypeId == thrift.BOOL { + if err = p.ReadField13(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 255: + if fieldTypeId == thrift.STRUCT { + if err = p.ReadField255(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + default: + if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + } + if err = iprot.ReadFieldEnd(); err != nil { + goto ReadFieldEndError + } + } + if err = iprot.ReadStructEnd(); err != nil { + goto ReadStructEndError + } + + return nil +ReadStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) +ReadFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) +ReadFieldError: + return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_CreateConversationRequest[fieldId]), err) +SkipFieldError: + return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) + +ReadFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) +ReadStructEndError: + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) +} + +func (p *CreateConversationRequest) ReadField1(iprot thrift.TProtocol) error { + _, _, size, err := iprot.ReadMapBegin() + if err != nil { + return err + } + _field := make(map[string]string, size) + for i := 0; i < size; i++ { + var _key string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _key = v + } + + var _val string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _val = v + } + + _field[_key] = _val + } + if err := iprot.ReadMapEnd(); err != nil { + return err + } + p.MetaData = _field + return nil +} +func (p *CreateConversationRequest) ReadField3(iprot thrift.TProtocol) error { + + var _field *int64 + if v, err := iprot.ReadI64(); err != nil { + return err + } else { + _field = &v + } + p.BotId = _field + return nil +} +func (p *CreateConversationRequest) ReadField4(iprot thrift.TProtocol) error { + + var _field *int64 + if v, err := iprot.ReadI64(); err != nil { + return err + } else { + _field = &v + } + p.ConnectorId = _field + return nil +} +func (p *CreateConversationRequest) ReadField5(iprot thrift.TProtocol) error { + + var _field *string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _field = &v + } + p.SpaceID = _field + return nil +} +func (p *CreateConversationRequest) ReadField9(iprot thrift.TProtocol) error { + + var _field *string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _field = &v + } + p.AppID = _field + return nil +} +func (p *CreateConversationRequest) ReadField10(iprot thrift.TProtocol) error { + + var _field *string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _field = &v + } + p.WorkflowID = _field + return nil +} +func (p *CreateConversationRequest) ReadField11(iprot thrift.TProtocol) error { + + var _field *string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _field = &v + } + p.ConversationMame = _field + return nil +} +func (p *CreateConversationRequest) ReadField12(iprot thrift.TProtocol) error { + + var _field *bool + if v, err := iprot.ReadBool(); err != nil { + return err + } else { + _field = &v + } + p.GetOrCreate = _field + return nil +} +func (p *CreateConversationRequest) ReadField13(iprot thrift.TProtocol) error { + + var _field *bool + if v, err := iprot.ReadBool(); err != nil { + return err + } else { + _field = &v + } + p.DraftMode = _field + return nil +} +func (p *CreateConversationRequest) ReadField255(iprot thrift.TProtocol) error { + _field := base.NewBase() + if err := _field.Read(iprot); err != nil { + return err + } + p.Base = _field + return nil +} + +func (p *CreateConversationRequest) Write(oprot thrift.TProtocol) (err error) { + var fieldId int16 + if err = oprot.WriteStructBegin("CreateConversationRequest"); err != nil { + goto WriteStructBeginError + } + if p != nil { + if err = p.writeField1(oprot); err != nil { + fieldId = 1 + goto WriteFieldError + } + if err = p.writeField3(oprot); err != nil { + fieldId = 3 + goto WriteFieldError + } + if err = p.writeField4(oprot); err != nil { + fieldId = 4 + goto WriteFieldError + } + if err = p.writeField5(oprot); err != nil { + fieldId = 5 + goto WriteFieldError + } + if err = p.writeField9(oprot); err != nil { + fieldId = 9 + goto WriteFieldError + } + if err = p.writeField10(oprot); err != nil { + fieldId = 10 + goto WriteFieldError + } + if err = p.writeField11(oprot); err != nil { + fieldId = 11 + goto WriteFieldError + } + if err = p.writeField12(oprot); err != nil { + fieldId = 12 + goto WriteFieldError + } + if err = p.writeField13(oprot); err != nil { + fieldId = 13 + goto WriteFieldError + } + if err = p.writeField255(oprot); err != nil { + fieldId = 255 + goto WriteFieldError + } + } + if err = oprot.WriteFieldStop(); err != nil { + goto WriteFieldStopError + } + if err = oprot.WriteStructEnd(); err != nil { + goto WriteStructEndError + } + return nil +WriteStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) +WriteFieldError: + return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) +WriteFieldStopError: + return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) +WriteStructEndError: + return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) +} + +func (p *CreateConversationRequest) writeField1(oprot thrift.TProtocol) (err error) { + if p.IsSetMetaData() { + if err = oprot.WriteFieldBegin("MetaData", thrift.MAP, 1); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteMapBegin(thrift.STRING, thrift.STRING, len(p.MetaData)); err != nil { + return err + } + for k, v := range p.MetaData { + if err := oprot.WriteString(k); err != nil { + return err + } + if err := oprot.WriteString(v); err != nil { + return err + } + } + if err := oprot.WriteMapEnd(); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) +} +func (p *CreateConversationRequest) writeField3(oprot thrift.TProtocol) (err error) { + if p.IsSetBotId() { + if err = oprot.WriteFieldBegin("BotId", thrift.I64, 3); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteI64(*p.BotId); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 3 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 3 end error: ", p), err) +} +func (p *CreateConversationRequest) writeField4(oprot thrift.TProtocol) (err error) { + if p.IsSetConnectorId() { + if err = oprot.WriteFieldBegin("ConnectorId", thrift.I64, 4); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteI64(*p.ConnectorId); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 4 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 4 end error: ", p), err) +} +func (p *CreateConversationRequest) writeField5(oprot thrift.TProtocol) (err error) { + if p.IsSetSpaceID() { + if err = oprot.WriteFieldBegin("SpaceID", thrift.STRING, 5); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteString(*p.SpaceID); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 5 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 5 end error: ", p), err) +} +func (p *CreateConversationRequest) writeField9(oprot thrift.TProtocol) (err error) { + if p.IsSetAppID() { + if err = oprot.WriteFieldBegin("AppID", thrift.STRING, 9); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteString(*p.AppID); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 9 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 9 end error: ", p), err) +} +func (p *CreateConversationRequest) writeField10(oprot thrift.TProtocol) (err error) { + if p.IsSetWorkflowID() { + if err = oprot.WriteFieldBegin("WorkflowID", thrift.STRING, 10); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteString(*p.WorkflowID); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 10 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 10 end error: ", p), err) +} +func (p *CreateConversationRequest) writeField11(oprot thrift.TProtocol) (err error) { + if p.IsSetConversationMame() { + if err = oprot.WriteFieldBegin("ConversationMame", thrift.STRING, 11); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteString(*p.ConversationMame); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 11 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 11 end error: ", p), err) +} +func (p *CreateConversationRequest) writeField12(oprot thrift.TProtocol) (err error) { + if p.IsSetGetOrCreate() { + if err = oprot.WriteFieldBegin("GetOrCreate", thrift.BOOL, 12); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteBool(*p.GetOrCreate); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 12 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 12 end error: ", p), err) +} +func (p *CreateConversationRequest) writeField13(oprot thrift.TProtocol) (err error) { + if p.IsSetDraftMode() { + if err = oprot.WriteFieldBegin("DraftMode", thrift.BOOL, 13); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteBool(*p.DraftMode); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 13 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 13 end error: ", p), err) +} +func (p *CreateConversationRequest) writeField255(oprot thrift.TProtocol) (err error) { + if p.IsSetBase() { + if err = oprot.WriteFieldBegin("Base", thrift.STRUCT, 255); err != nil { + goto WriteFieldBeginError + } + if err := p.Base.Write(oprot); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 255 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 255 end error: ", p), err) +} + +func (p *CreateConversationRequest) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("CreateConversationRequest(%+v)", *p) + +} + +type CreateConversationResponse struct { + Code int64 `thrift:"code,1" form:"code" json:"code" query:"code"` + Msg string `thrift:"msg,2" form:"msg" json:"msg" query:"msg"` + ConversationData *ConversationData `thrift:"ConversationData,3,optional" form:"data" json:"data,omitempty"` +} + +func NewCreateConversationResponse() *CreateConversationResponse { + return &CreateConversationResponse{} +} + +func (p *CreateConversationResponse) InitDefault() { +} + +func (p *CreateConversationResponse) GetCode() (v int64) { + return p.Code +} + +func (p *CreateConversationResponse) GetMsg() (v string) { + return p.Msg +} + +var CreateConversationResponse_ConversationData_DEFAULT *ConversationData + +func (p *CreateConversationResponse) GetConversationData() (v *ConversationData) { + if !p.IsSetConversationData() { + return CreateConversationResponse_ConversationData_DEFAULT + } + return p.ConversationData +} + +var fieldIDToName_CreateConversationResponse = map[int16]string{ + 1: "code", + 2: "msg", + 3: "ConversationData", +} + +func (p *CreateConversationResponse) IsSetConversationData() bool { + return p.ConversationData != nil +} + +func (p *CreateConversationResponse) Read(iprot thrift.TProtocol) (err error) { + var fieldTypeId thrift.TType + var fieldId int16 + + if _, err = iprot.ReadStructBegin(); err != nil { + goto ReadStructBeginError + } + + for { + _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() + if err != nil { + goto ReadFieldBeginError + } + if fieldTypeId == thrift.STOP { + break + } + + switch fieldId { + case 1: + if fieldTypeId == thrift.I64 { + if err = p.ReadField1(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 2: + if fieldTypeId == thrift.STRING { + if err = p.ReadField2(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 3: + if fieldTypeId == thrift.STRUCT { + if err = p.ReadField3(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + default: + if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + } + if err = iprot.ReadFieldEnd(); err != nil { + goto ReadFieldEndError + } + } + if err = iprot.ReadStructEnd(); err != nil { + goto ReadStructEndError + } + + return nil +ReadStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) +ReadFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) +ReadFieldError: + return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_CreateConversationResponse[fieldId]), err) +SkipFieldError: + return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) + +ReadFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) +ReadStructEndError: + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) +} + +func (p *CreateConversationResponse) ReadField1(iprot thrift.TProtocol) error { + + var _field int64 + if v, err := iprot.ReadI64(); err != nil { + return err + } else { + _field = v + } + p.Code = _field + return nil +} +func (p *CreateConversationResponse) ReadField2(iprot thrift.TProtocol) error { + + var _field string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _field = v + } + p.Msg = _field + return nil +} +func (p *CreateConversationResponse) ReadField3(iprot thrift.TProtocol) error { + _field := NewConversationData() + if err := _field.Read(iprot); err != nil { + return err + } + p.ConversationData = _field + return nil +} + +func (p *CreateConversationResponse) Write(oprot thrift.TProtocol) (err error) { + var fieldId int16 + if err = oprot.WriteStructBegin("CreateConversationResponse"); err != nil { + goto WriteStructBeginError + } + if p != nil { + if err = p.writeField1(oprot); err != nil { + fieldId = 1 + goto WriteFieldError + } + if err = p.writeField2(oprot); err != nil { + fieldId = 2 + goto WriteFieldError + } + if err = p.writeField3(oprot); err != nil { + fieldId = 3 + goto WriteFieldError + } + } + if err = oprot.WriteFieldStop(); err != nil { + goto WriteFieldStopError + } + if err = oprot.WriteStructEnd(); err != nil { + goto WriteStructEndError + } + return nil +WriteStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) +WriteFieldError: + return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) +WriteFieldStopError: + return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) +WriteStructEndError: + return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) +} + +func (p *CreateConversationResponse) writeField1(oprot thrift.TProtocol) (err error) { + if err = oprot.WriteFieldBegin("code", thrift.I64, 1); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteI64(p.Code); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) +} +func (p *CreateConversationResponse) writeField2(oprot thrift.TProtocol) (err error) { + if err = oprot.WriteFieldBegin("msg", thrift.STRING, 2); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteString(p.Msg); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 2 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 2 end error: ", p), err) +} +func (p *CreateConversationResponse) writeField3(oprot thrift.TProtocol) (err error) { + if p.IsSetConversationData() { + if err = oprot.WriteFieldBegin("ConversationData", thrift.STRUCT, 3); err != nil { + goto WriteFieldBeginError + } + if err := p.ConversationData.Write(oprot); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 3 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 3 end error: ", p), err) +} + +func (p *CreateConversationResponse) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("CreateConversationResponse(%+v)", *p) + +} + +type ConversationData struct { + Id int64 `thrift:"Id,1" form:"id" json:"id,string"` + CreatedAt int64 `thrift:"CreatedAt,2" form:"created_at" json:"created_at"` + MetaData map[string]string `thrift:"MetaData,3" form:"meta_data" json:"meta_data"` + CreatorID *int64 `thrift:"CreatorID,4,optional" form:"creator_d" json:"creator_d,string,omitempty"` + ConnectorID *int64 `thrift:"ConnectorID,5,optional" form:"connector_id" json:"connector_id,string,omitempty"` + LastSectionID *int64 `thrift:"LastSectionID,6,optional" form:"last_section_id" json:"last_section_id,string,omitempty"` + AccountID *int64 `thrift:"AccountID,7,optional" form:"account_id" json:"account_id,omitempty"` +} + +func NewConversationData() *ConversationData { + return &ConversationData{} +} + +func (p *ConversationData) InitDefault() { +} + +func (p *ConversationData) GetId() (v int64) { + return p.Id +} + +func (p *ConversationData) GetCreatedAt() (v int64) { + return p.CreatedAt +} + +func (p *ConversationData) GetMetaData() (v map[string]string) { + return p.MetaData +} + +var ConversationData_CreatorID_DEFAULT int64 + +func (p *ConversationData) GetCreatorID() (v int64) { + if !p.IsSetCreatorID() { + return ConversationData_CreatorID_DEFAULT + } + return *p.CreatorID +} + +var ConversationData_ConnectorID_DEFAULT int64 + +func (p *ConversationData) GetConnectorID() (v int64) { + if !p.IsSetConnectorID() { + return ConversationData_ConnectorID_DEFAULT + } + return *p.ConnectorID +} + +var ConversationData_LastSectionID_DEFAULT int64 + +func (p *ConversationData) GetLastSectionID() (v int64) { + if !p.IsSetLastSectionID() { + return ConversationData_LastSectionID_DEFAULT + } + return *p.LastSectionID +} + +var ConversationData_AccountID_DEFAULT int64 + +func (p *ConversationData) GetAccountID() (v int64) { + if !p.IsSetAccountID() { + return ConversationData_AccountID_DEFAULT + } + return *p.AccountID +} + +var fieldIDToName_ConversationData = map[int16]string{ + 1: "Id", + 2: "CreatedAt", + 3: "MetaData", + 4: "CreatorID", + 5: "ConnectorID", + 6: "LastSectionID", + 7: "AccountID", +} + +func (p *ConversationData) IsSetCreatorID() bool { + return p.CreatorID != nil +} + +func (p *ConversationData) IsSetConnectorID() bool { + return p.ConnectorID != nil +} + +func (p *ConversationData) IsSetLastSectionID() bool { + return p.LastSectionID != nil +} + +func (p *ConversationData) IsSetAccountID() bool { + return p.AccountID != nil +} + +func (p *ConversationData) Read(iprot thrift.TProtocol) (err error) { + var fieldTypeId thrift.TType + var fieldId int16 + + if _, err = iprot.ReadStructBegin(); err != nil { + goto ReadStructBeginError + } + + for { + _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() + if err != nil { + goto ReadFieldBeginError + } + if fieldTypeId == thrift.STOP { + break + } + + switch fieldId { + case 1: + if fieldTypeId == thrift.I64 { + if err = p.ReadField1(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 2: + if fieldTypeId == thrift.I64 { + if err = p.ReadField2(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 3: + if fieldTypeId == thrift.MAP { + if err = p.ReadField3(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 4: + if fieldTypeId == thrift.I64 { + if err = p.ReadField4(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 5: + if fieldTypeId == thrift.I64 { + if err = p.ReadField5(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 6: + if fieldTypeId == thrift.I64 { + if err = p.ReadField6(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 7: + if fieldTypeId == thrift.I64 { + if err = p.ReadField7(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + default: + if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + } + if err = iprot.ReadFieldEnd(); err != nil { + goto ReadFieldEndError + } + } + if err = iprot.ReadStructEnd(); err != nil { + goto ReadStructEndError + } + + return nil +ReadStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) +ReadFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) +ReadFieldError: + return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_ConversationData[fieldId]), err) +SkipFieldError: + return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) + +ReadFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) +ReadStructEndError: + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) +} + +func (p *ConversationData) ReadField1(iprot thrift.TProtocol) error { + + var _field int64 + if v, err := iprot.ReadI64(); err != nil { + return err + } else { + _field = v + } + p.Id = _field + return nil +} +func (p *ConversationData) ReadField2(iprot thrift.TProtocol) error { + + var _field int64 + if v, err := iprot.ReadI64(); err != nil { + return err + } else { + _field = v + } + p.CreatedAt = _field + return nil +} +func (p *ConversationData) ReadField3(iprot thrift.TProtocol) error { + _, _, size, err := iprot.ReadMapBegin() + if err != nil { + return err + } + _field := make(map[string]string, size) + for i := 0; i < size; i++ { + var _key string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _key = v + } + + var _val string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _val = v + } + + _field[_key] = _val + } + if err := iprot.ReadMapEnd(); err != nil { + return err + } + p.MetaData = _field + return nil +} +func (p *ConversationData) ReadField4(iprot thrift.TProtocol) error { + + var _field *int64 + if v, err := iprot.ReadI64(); err != nil { + return err + } else { + _field = &v + } + p.CreatorID = _field + return nil +} +func (p *ConversationData) ReadField5(iprot thrift.TProtocol) error { + + var _field *int64 + if v, err := iprot.ReadI64(); err != nil { + return err + } else { + _field = &v + } + p.ConnectorID = _field + return nil +} +func (p *ConversationData) ReadField6(iprot thrift.TProtocol) error { + + var _field *int64 + if v, err := iprot.ReadI64(); err != nil { + return err + } else { + _field = &v + } + p.LastSectionID = _field + return nil +} +func (p *ConversationData) ReadField7(iprot thrift.TProtocol) error { + + var _field *int64 + if v, err := iprot.ReadI64(); err != nil { + return err + } else { + _field = &v + } + p.AccountID = _field + return nil +} + +func (p *ConversationData) Write(oprot thrift.TProtocol) (err error) { + var fieldId int16 + if err = oprot.WriteStructBegin("ConversationData"); err != nil { + goto WriteStructBeginError + } + if p != nil { + if err = p.writeField1(oprot); err != nil { + fieldId = 1 + goto WriteFieldError + } + if err = p.writeField2(oprot); err != nil { + fieldId = 2 + goto WriteFieldError + } + if err = p.writeField3(oprot); err != nil { + fieldId = 3 + goto WriteFieldError + } + if err = p.writeField4(oprot); err != nil { + fieldId = 4 + goto WriteFieldError + } + if err = p.writeField5(oprot); err != nil { + fieldId = 5 + goto WriteFieldError + } + if err = p.writeField6(oprot); err != nil { + fieldId = 6 + goto WriteFieldError + } + if err = p.writeField7(oprot); err != nil { + fieldId = 7 + goto WriteFieldError + } + } + if err = oprot.WriteFieldStop(); err != nil { + goto WriteFieldStopError + } + if err = oprot.WriteStructEnd(); err != nil { + goto WriteStructEndError + } + return nil +WriteStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) +WriteFieldError: + return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) +WriteFieldStopError: + return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) +WriteStructEndError: + return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) +} + +func (p *ConversationData) writeField1(oprot thrift.TProtocol) (err error) { + if err = oprot.WriteFieldBegin("Id", thrift.I64, 1); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteI64(p.Id); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) +} +func (p *ConversationData) writeField2(oprot thrift.TProtocol) (err error) { + if err = oprot.WriteFieldBegin("CreatedAt", thrift.I64, 2); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteI64(p.CreatedAt); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 2 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 2 end error: ", p), err) +} +func (p *ConversationData) writeField3(oprot thrift.TProtocol) (err error) { + if err = oprot.WriteFieldBegin("MetaData", thrift.MAP, 3); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteMapBegin(thrift.STRING, thrift.STRING, len(p.MetaData)); err != nil { + return err + } + for k, v := range p.MetaData { + if err := oprot.WriteString(k); err != nil { + return err + } + if err := oprot.WriteString(v); err != nil { + return err + } + } + if err := oprot.WriteMapEnd(); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 3 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 3 end error: ", p), err) +} +func (p *ConversationData) writeField4(oprot thrift.TProtocol) (err error) { + if p.IsSetCreatorID() { + if err = oprot.WriteFieldBegin("CreatorID", thrift.I64, 4); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteI64(*p.CreatorID); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 4 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 4 end error: ", p), err) +} +func (p *ConversationData) writeField5(oprot thrift.TProtocol) (err error) { + if p.IsSetConnectorID() { + if err = oprot.WriteFieldBegin("ConnectorID", thrift.I64, 5); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteI64(*p.ConnectorID); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 5 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 5 end error: ", p), err) +} +func (p *ConversationData) writeField6(oprot thrift.TProtocol) (err error) { + if p.IsSetLastSectionID() { + if err = oprot.WriteFieldBegin("LastSectionID", thrift.I64, 6); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteI64(*p.LastSectionID); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 6 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 6 end error: ", p), err) +} +func (p *ConversationData) writeField7(oprot thrift.TProtocol) (err error) { + if p.IsSetAccountID() { + if err = oprot.WriteFieldBegin("AccountID", thrift.I64, 7); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteI64(*p.AccountID); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 7 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 7 end error: ", p), err) +} + +func (p *ConversationData) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("ConversationData(%+v)", *p) + +} diff --git a/backend/api/model/workflow/workflow_svc.go b/backend/api/model/workflow/workflow_svc.go index 6035fd9d7..c184890e1 100644 --- a/backend/api/model/workflow/workflow_svc.go +++ b/backend/api/model/workflow/workflow_svc.go @@ -1,3 +1,19 @@ +/* + * Copyright 2025 coze-dev Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + // Code generated by thriftgo (0.4.1). DO NOT EDIT. package workflow @@ -106,6 +122,8 @@ type WorkflowService interface { OpenAPIChatFlowRun(ctx context.Context, request *ChatFlowRunRequest) (r *ChatFlowRunResponse, err error) OpenAPIGetWorkflowInfo(ctx context.Context, request *OpenAPIGetWorkflowInfoRequest) (r *OpenAPIGetWorkflowInfoResponse, err error) + + OpenAPICreateConversation(ctx context.Context, request *CreateConversationRequest) (r *CreateConversationRequest, err error) } type WorkflowServiceClient struct { @@ -566,6 +584,15 @@ func (p *WorkflowServiceClient) OpenAPIGetWorkflowInfo(ctx context.Context, requ } return _result.GetSuccess(), nil } +func (p *WorkflowServiceClient) OpenAPICreateConversation(ctx context.Context, request *CreateConversationRequest) (r *CreateConversationRequest, err error) { + var _args WorkflowServiceOpenAPICreateConversationArgs + _args.Request = request + var _result WorkflowServiceOpenAPICreateConversationResult + if err = p.Client_().Call(ctx, "OpenAPICreateConversation", &_args, &_result); err != nil { + return + } + return _result.GetSuccess(), nil +} type WorkflowServiceProcessor struct { processorMap map[string]thrift.TProcessorFunction @@ -635,6 +662,7 @@ func NewWorkflowServiceProcessor(handler WorkflowService) *WorkflowServiceProces self.AddToProcessorMap("OpenAPIGetWorkflowRunHistory", &workflowServiceProcessorOpenAPIGetWorkflowRunHistory{handler: handler}) self.AddToProcessorMap("OpenAPIChatFlowRun", &workflowServiceProcessorOpenAPIChatFlowRun{handler: handler}) self.AddToProcessorMap("OpenAPIGetWorkflowInfo", &workflowServiceProcessorOpenAPIGetWorkflowInfo{handler: handler}) + self.AddToProcessorMap("OpenAPICreateConversation", &workflowServiceProcessorOpenAPICreateConversation{handler: handler}) return self } func (p *WorkflowServiceProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { @@ -2959,6 +2987,54 @@ func (p *workflowServiceProcessorOpenAPIGetWorkflowInfo) Process(ctx context.Con return true, err } +type workflowServiceProcessorOpenAPICreateConversation struct { + handler WorkflowService +} + +func (p *workflowServiceProcessorOpenAPICreateConversation) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + args := WorkflowServiceOpenAPICreateConversationArgs{} + if err = args.Read(iprot); err != nil { + iprot.ReadMessageEnd() + x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) + oprot.WriteMessageBegin("OpenAPICreateConversation", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush(ctx) + return false, err + } + + iprot.ReadMessageEnd() + var err2 error + result := WorkflowServiceOpenAPICreateConversationResult{} + var retval *CreateConversationRequest + if retval, err2 = p.handler.OpenAPICreateConversation(ctx, args.Request); err2 != nil { + x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing OpenAPICreateConversation: "+err2.Error()) + oprot.WriteMessageBegin("OpenAPICreateConversation", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush(ctx) + return true, err2 + } else { + result.Success = retval + } + if err2 = oprot.WriteMessageBegin("OpenAPICreateConversation", thrift.REPLY, seqId); err2 != nil { + err = err2 + } + if err2 = result.Write(oprot); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.Flush(ctx); err == nil && err2 != nil { + err = err2 + } + if err != nil { + return + } + return true, err +} + type WorkflowServiceCreateWorkflowArgs struct { Request *CreateWorkflowRequest `thrift:"request,1"` } @@ -16974,3 +17050,295 @@ func (p *WorkflowServiceOpenAPIGetWorkflowInfoResult) String() string { return fmt.Sprintf("WorkflowServiceOpenAPIGetWorkflowInfoResult(%+v)", *p) } + +type WorkflowServiceOpenAPICreateConversationArgs struct { + Request *CreateConversationRequest `thrift:"request,1"` +} + +func NewWorkflowServiceOpenAPICreateConversationArgs() *WorkflowServiceOpenAPICreateConversationArgs { + return &WorkflowServiceOpenAPICreateConversationArgs{} +} + +func (p *WorkflowServiceOpenAPICreateConversationArgs) InitDefault() { +} + +var WorkflowServiceOpenAPICreateConversationArgs_Request_DEFAULT *CreateConversationRequest + +func (p *WorkflowServiceOpenAPICreateConversationArgs) GetRequest() (v *CreateConversationRequest) { + if !p.IsSetRequest() { + return WorkflowServiceOpenAPICreateConversationArgs_Request_DEFAULT + } + return p.Request +} + +var fieldIDToName_WorkflowServiceOpenAPICreateConversationArgs = map[int16]string{ + 1: "request", +} + +func (p *WorkflowServiceOpenAPICreateConversationArgs) IsSetRequest() bool { + return p.Request != nil +} + +func (p *WorkflowServiceOpenAPICreateConversationArgs) Read(iprot thrift.TProtocol) (err error) { + var fieldTypeId thrift.TType + var fieldId int16 + + if _, err = iprot.ReadStructBegin(); err != nil { + goto ReadStructBeginError + } + + for { + _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() + if err != nil { + goto ReadFieldBeginError + } + if fieldTypeId == thrift.STOP { + break + } + + switch fieldId { + case 1: + if fieldTypeId == thrift.STRUCT { + if err = p.ReadField1(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + default: + if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + } + if err = iprot.ReadFieldEnd(); err != nil { + goto ReadFieldEndError + } + } + if err = iprot.ReadStructEnd(); err != nil { + goto ReadStructEndError + } + + return nil +ReadStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) +ReadFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) +ReadFieldError: + return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_WorkflowServiceOpenAPICreateConversationArgs[fieldId]), err) +SkipFieldError: + return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) + +ReadFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) +ReadStructEndError: + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) +} + +func (p *WorkflowServiceOpenAPICreateConversationArgs) ReadField1(iprot thrift.TProtocol) error { + _field := NewCreateConversationRequest() + if err := _field.Read(iprot); err != nil { + return err + } + p.Request = _field + return nil +} + +func (p *WorkflowServiceOpenAPICreateConversationArgs) Write(oprot thrift.TProtocol) (err error) { + var fieldId int16 + if err = oprot.WriteStructBegin("OpenAPICreateConversation_args"); err != nil { + goto WriteStructBeginError + } + if p != nil { + if err = p.writeField1(oprot); err != nil { + fieldId = 1 + goto WriteFieldError + } + } + if err = oprot.WriteFieldStop(); err != nil { + goto WriteFieldStopError + } + if err = oprot.WriteStructEnd(); err != nil { + goto WriteStructEndError + } + return nil +WriteStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) +WriteFieldError: + return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) +WriteFieldStopError: + return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) +WriteStructEndError: + return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) +} + +func (p *WorkflowServiceOpenAPICreateConversationArgs) writeField1(oprot thrift.TProtocol) (err error) { + if err = oprot.WriteFieldBegin("request", thrift.STRUCT, 1); err != nil { + goto WriteFieldBeginError + } + if err := p.Request.Write(oprot); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) +} + +func (p *WorkflowServiceOpenAPICreateConversationArgs) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("WorkflowServiceOpenAPICreateConversationArgs(%+v)", *p) + +} + +type WorkflowServiceOpenAPICreateConversationResult struct { + Success *CreateConversationRequest `thrift:"success,0,optional"` +} + +func NewWorkflowServiceOpenAPICreateConversationResult() *WorkflowServiceOpenAPICreateConversationResult { + return &WorkflowServiceOpenAPICreateConversationResult{} +} + +func (p *WorkflowServiceOpenAPICreateConversationResult) InitDefault() { +} + +var WorkflowServiceOpenAPICreateConversationResult_Success_DEFAULT *CreateConversationRequest + +func (p *WorkflowServiceOpenAPICreateConversationResult) GetSuccess() (v *CreateConversationRequest) { + if !p.IsSetSuccess() { + return WorkflowServiceOpenAPICreateConversationResult_Success_DEFAULT + } + return p.Success +} + +var fieldIDToName_WorkflowServiceOpenAPICreateConversationResult = map[int16]string{ + 0: "success", +} + +func (p *WorkflowServiceOpenAPICreateConversationResult) IsSetSuccess() bool { + return p.Success != nil +} + +func (p *WorkflowServiceOpenAPICreateConversationResult) Read(iprot thrift.TProtocol) (err error) { + var fieldTypeId thrift.TType + var fieldId int16 + + if _, err = iprot.ReadStructBegin(); err != nil { + goto ReadStructBeginError + } + + for { + _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() + if err != nil { + goto ReadFieldBeginError + } + if fieldTypeId == thrift.STOP { + break + } + + switch fieldId { + case 0: + if fieldTypeId == thrift.STRUCT { + if err = p.ReadField0(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + default: + if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + } + if err = iprot.ReadFieldEnd(); err != nil { + goto ReadFieldEndError + } + } + if err = iprot.ReadStructEnd(); err != nil { + goto ReadStructEndError + } + + return nil +ReadStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) +ReadFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) +ReadFieldError: + return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_WorkflowServiceOpenAPICreateConversationResult[fieldId]), err) +SkipFieldError: + return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) + +ReadFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) +ReadStructEndError: + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) +} + +func (p *WorkflowServiceOpenAPICreateConversationResult) ReadField0(iprot thrift.TProtocol) error { + _field := NewCreateConversationRequest() + if err := _field.Read(iprot); err != nil { + return err + } + p.Success = _field + return nil +} + +func (p *WorkflowServiceOpenAPICreateConversationResult) Write(oprot thrift.TProtocol) (err error) { + var fieldId int16 + if err = oprot.WriteStructBegin("OpenAPICreateConversation_result"); err != nil { + goto WriteStructBeginError + } + if p != nil { + if err = p.writeField0(oprot); err != nil { + fieldId = 0 + goto WriteFieldError + } + } + if err = oprot.WriteFieldStop(); err != nil { + goto WriteFieldStopError + } + if err = oprot.WriteStructEnd(); err != nil { + goto WriteStructEndError + } + return nil +WriteStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) +WriteFieldError: + return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) +WriteFieldStopError: + return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) +WriteStructEndError: + return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) +} + +func (p *WorkflowServiceOpenAPICreateConversationResult) writeField0(oprot thrift.TProtocol) (err error) { + if p.IsSetSuccess() { + if err = oprot.WriteFieldBegin("success", thrift.STRUCT, 0); err != nil { + goto WriteFieldBeginError + } + if err := p.Success.Write(oprot); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 0 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 0 end error: ", p), err) +} + +func (p *WorkflowServiceOpenAPICreateConversationResult) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("WorkflowServiceOpenAPICreateConversationResult(%+v)", *p) + +} diff --git a/backend/api/router/coze/api.go b/backend/api/router/coze/api.go index d3ee72cb1..2fbeb5a01 100644 --- a/backend/api/router/coze/api.go +++ b/backend/api/router/coze/api.go @@ -1,3 +1,19 @@ +/* + * Copyright 2025 coze-dev Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + // Code generated by hertz generator. DO NOT EDIT. package coze @@ -438,6 +454,10 @@ func Register(r *server.Hertz) { _workflow.POST("/run", append(_openapirunflowMw(), coze.OpenAPIRunFlow)...) _workflow.POST("/stream_resume", append(_openapistreamresumeflowMw(), coze.OpenAPIStreamResumeFlow)...) _workflow.POST("/stream_run", append(_openapistreamrunflowMw(), coze.OpenAPIStreamRunFlow)...) + { + _conversation1 := _workflow.Group("/conversation", _conversation1Mw()...) + _conversation1.POST("/create", append(_openapicreateconversationMw(), coze.OpenAPICreateConversation)...) + } } { _workflows := _v1.Group("/workflows", _workflowsMw()...) diff --git a/backend/api/router/coze/middleware.go b/backend/api/router/coze/middleware.go index f5a35a4d9..293475293 100644 --- a/backend/api/router/coze/middleware.go +++ b/backend/api/router/coze/middleware.go @@ -1505,3 +1505,18 @@ func _upload1Mw() []app.HandlerFunc { // your code... return nil } + +func _getorcreateconversationMw() []app.HandlerFunc { + // your code... + return nil +} + +func _conversation1Mw() []app.HandlerFunc { + // your code... + return nil +} + +func _openapicreateconversationMw() []app.HandlerFunc { + // your code... + return nil +} diff --git a/backend/api/router/register.go b/backend/api/router/register.go index 0b1a2d418..f6e787c7a 100644 --- a/backend/api/router/register.go +++ b/backend/api/router/register.go @@ -20,6 +20,7 @@ package router import ( "context" + "net/http" "os" "path" "strings" @@ -74,4 +75,17 @@ func staticFileRegister(r *server.Hertz) { ctx.File(staticFile) }) + r.Handle(http.MethodPost, "api/permission_api/coze_web_app/impersonate_coze_user", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(200, map[string]any{ + "code": 0, + "msg": "ok", + "data": map[string]interface{}{ + "access_token": "pat_ab1212d883ba6e0a63c28dd47a6e13629f7d5885b78b55d933e9caf9aae737c2", + "expires_in": 1753998220, + "token_type": "Bearer", + }, + }) + + }) + } diff --git a/backend/application/workflow/chatflow.go b/backend/application/workflow/chatflow.go index 7c4302710..654f81175 100644 --- a/backend/application/workflow/chatflow.go +++ b/backend/application/workflow/chatflow.go @@ -18,14 +18,17 @@ package workflow import ( "context" + "errors" "fmt" - "github.com/coze-dev/coze-studio/backend/types/consts" - "runtime/debug" "strconv" + "strings" + "github.com/cloudwego/eino/schema" + "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message" "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow" "github.com/coze-dev/coze-studio/backend/application/base/ctxutil" + "github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossmessage" "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" @@ -33,10 +36,203 @@ import ( "github.com/coze-dev/coze-studio/backend/pkg/lang/ptr" "github.com/coze-dev/coze-studio/backend/pkg/lang/slices" "github.com/coze-dev/coze-studio/backend/pkg/lang/ternary" + "github.com/coze-dev/coze-studio/backend/pkg/logs" "github.com/coze-dev/coze-studio/backend/pkg/safego" + "github.com/coze-dev/coze-studio/backend/pkg/sonic" + "github.com/coze-dev/coze-studio/backend/pkg/taskgroup" + "github.com/coze-dev/coze-studio/backend/types/consts" "github.com/coze-dev/coze-studio/backend/types/errno" ) +const ( + userRole = "user" + assistantRole = "assistant" + cardTemplate = ` +{ + "elements": { + "root": { + "id": "root", + "name": "Root", + "type": "@flowpd/cici-components/PageContainer", + "props": { + "backgroundColor": "grey", + "containerPadding": 16, + "containerRowGap": 12 + }, + "children": [ + "OpfZnYNHby", + "70zV0Jp5vy" + ], + "directives": { + + } + }, + "OpfZnYNHby": { + "id": "OpfZnYNHby", + "name": "FlowpdCiciComponentsColumnLayout", + "type": "@flowpd/cici-components/ColumnLayout", + "props": { + "backgroundColor": "transparent", + "layoutColumnGap": 4, + "layoutPaddingGap": 2, + "borderRadius": 0, + "enableClickEvent": false, + "action": "enableUrl", + "Columns": [ + { + "type": "slot", + "children": [ + "KPa0BqoODo" + ], + "config": { + "width": "weighted", + "weight": 1, + "vertical": "top", + "horizontal": "left", + "columnElementGap": 4, + "columnElementPadding": 2, + "enableClickEvent": false + } + } + ] + }, + "children": [ + + ], + "directives": { + "repeat": { + "type": "expression", + "value": "{{5fJt3qKpSz}}", + "replaceMap": { + "5fJt3qKpSz": "list" + } + } + } + }, + "KPa0BqoODo": { + "id": "KPa0BqoODo", + "name": "FlowpdCiciComponentsInput", + "type": "@flowpd/cici-components/Input", + "props": { + "enableLabel": true, + "label": { + "type": "expression", + "value": "{{item.name}}" + }, + "placeholder": "Please enter content.", + "maxLengthEnabled": false, + "maxLength": 140, + "required": false, + "enableSendIcon": true, + "actionType": "enableMessage", + "disableAfterAction": true, + "message": { + "type": "expression", + "value": "{{KPa0BqoODo_value}}" + } + }, + "children": [ + + ], + "directives": { + + } + }, + "70zV0Jp5vy": { + "id": "70zV0Jp5vy", + "name": "FlowpdCiciComponentsColumnLayout", + "type": "@flowpd/cici-components/ColumnLayout", + "props": { + "backgroundColor": "transparent", + "layoutColumnGap": 4, + "layoutPaddingGap": 2, + "borderRadius": 0, + "enableClickEvent": false, + "action": "enableUrl", + "Columns": [ + { + "type": "slot", + "children": [ + "mH5BNaFTl1" + ], + "config": { + "width": "weighted", + "weight": 1, + "vertical": "top", + "horizontal": "right", + "columnElementGap": 4, + "columnElementPadding": 2, + "enableClickEvent": false + } + } + ] + }, + "children": [ + + ], + "directives": { + + } + }, + "mH5BNaFTl1": { + "id": "mH5BNaFTl1", + "name": "FlowpdCiciComponentsButton", + "type": "@flowpd/cici-components/Button", + "props": { + "content": "Button", + "type": "primary", + "size": "small", + "width": "hug", + "widthPx": 160, + "textAlign": "center", + "enableLines": false, + "lines": 1, + "positionStyle": { + "type": "default" + }, + "actionType": "enableMessage", + "disableAfterAction": true, + "message": { + "type": "expression", + "value": "{{KPa0BqoODo_value}}" + } + }, + "children": [ + + ], + "directives": { + + } + } + }, + "rootID": "root", + "variables": { + "5fJt3qKpSz": { + "id": "5fJt3qKpSz", + "name": "list", + "defaultValue": [ + + ] + } + }, + "actions": { + + } +}` +) + +type inputCard struct { + Elements any `json:"elements"` + RootID string `json:"rootID"` + Variables map[string]any `json:"variables"` +} + +func defaultCard() *inputCard { + card := &inputCard{} + _ = sonic.UnmarshalString(cardTemplate, card) + return card +} + func (w *ApplicationService) CreateApplicationConversationDef(ctx context.Context, req *workflow.CreateProjectConversationDefRequest) (resp *workflow.CreateProjectConversationDefResponse, err error) { defer func() { if panicErr := recover(); panicErr != nil { @@ -262,3 +458,897 @@ func (w *ApplicationService) ListApplicationConversationDef(ctx context.Context, return resp, nil } + +func (w *ApplicationService) OpenAPIChatFlowRun(ctx context.Context, req *workflow.ChatFlowRunRequest) ( + _ *schema.StreamReader[[]*workflow.ChatFlowRunResponse], err error) { + defer func() { + if panicErr := recover(); panicErr != nil { + err = safego.NewPanicErr(panicErr, debug.Stack()) + } + + if err != nil { + err = vo.WrapIfNeeded(errno.ErrChatFlowRoleOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error())) + } + }() + + if len(req.GetAdditionalMessages()) == 0 { + return nil, fmt.Errorf("additional_messages is requird") + } + + messages := req.GetAdditionalMessages() + + lastUserMessage := messages[len(req.GetAdditionalMessages())-1] + if lastUserMessage.Role != userRole { + return nil, errors.New("the role of the last day message must be user") + } + + var parameters = make(map[string]any) + if len(req.GetParameters()) > 0 { + err := sonic.UnmarshalString(req.GetParameters(), parameters) + if err != nil { + return nil, err + } + } + + var ( + isDebug = req.GetExecuteMode() == "DEBUG" + appID, agentID *int64 + resolveAppID int64 + connectorID, userID, conversationID int64 + version string + locator vo.Locator + ) + if req.IsSetAppID() { + appID = ptr.Of(mustParseInt64(req.GetAppID())) + resolveAppID = mustParseInt64(req.GetAppID()) + } + if req.IsSetBotID() { + agentID = ptr.Of(mustParseInt64(req.GetBotID())) + resolveAppID = mustParseInt64(req.GetBotID()) + } + + if appID != nil && agentID != nil { + return nil, errors.New("project_id and bot_id cannot be set at the same time") + } + + if isDebug { + userID = ctxutil.MustGetUIDFromCtx(ctx) + connectorID = mustParseInt64(req.GetConnectorID()) + locator = vo.FromDraft + + } else { + apiKeyInfo := ctxutil.GetApiAuthFromCtx(ctx) + userID = apiKeyInfo.UserID + connectorID = apiKeyInfo.ConnectorID + meta, err := GetWorkflowDomainSVC().Get(ctx, &vo.GetPolicy{ + ID: mustParseInt64(req.GetWorkflowID()), + MetaOnly: true, + }) + if err != nil { + return nil, err + } + + if meta.LatestPublishedVersion == nil { + return nil, vo.NewError(errno.ErrWorkflowNotPublished) + } + if req.IsSetVersion() { + version = req.GetVersion() + locator = vo.FromSpecificVersion + } else { + version = meta.GetLatestVersion() + locator = vo.FromLatestVersion + } + } + + if req.IsSetConversationID() { + conversationID = mustParseInt64(req.GetConversationID()) + } else { + conversationName, ok := parameters["CONVERSATION_NAME"].(string) + if !ok { + return nil, fmt.Errorf("conversation name is requried") + } + cID, err := GetWorkflowDomainSVC().GetOrCreateConversation(ctx, ternary.IFElse(isDebug, vo.Draft, vo.Online), resolveAppID, connectorID, userID, conversationName) + if err != nil { + return nil, err + } + conversationID = cID + } + + roundID, err := w.IDGenerator.GenID(ctx) + if err != nil { + return nil, vo.WrapError(errno.ErrIDGenError, err) + } + + userMessage, err := toConversationMessage(ctx, resolveAppID, conversationID, userID, roundID, message.MessageTypeQuestion, lastUserMessage) + if err != nil { + return nil, err + } + + messageClient := crossmessage.DefaultSVC() + _, err = messageClient.Create(ctx, userMessage) + if err != nil { + return nil, err + } + + info, existed, unbinding, err := GetWorkflowDomainSVC().GetConvRelatedInfo(ctx, conversationID) + if err != nil { + return nil, err + } + + if existed { + var data = lastUserMessage.Content + if info.NodeType == entity.NodeTypeInputReceiver { + data = parserInput(lastUserMessage.Content) + } + sr, err := GetWorkflowDomainSVC().StreamResume(ctx, &entity.ResumeRequest{ + EventID: info.EventID, + ExecuteID: info.ExecID, + ResumeData: data, + }, vo.ExecuteConfig{ + Operator: userID, + Mode: ternary.IFElse(isDebug, vo.ExecuteModeDebug, vo.ExecuteModeRelease), + ConnectorID: connectorID, + ConnectorUID: strconv.FormatInt(userID, 10), + BizType: vo.BizTypeWorkflow, + AppID: appID, + AgentID: agentID, + ConversationID: ptr.Of(conversationID), + RoundID: ptr.Of(roundID), + }) + if err != nil { + uErr := unbinding() + if uErr != nil { + return nil, uErr + } + return nil, err + } + + return schema.StreamReaderWithConvert(sr, convertToChatFlowRunResponseList(ctx, convertToChatFlowInfo{ + appID: resolveAppID, + conversationID: conversationID, + roundID: roundID, + workflowID: mustParseInt64(req.GetWorkflowID()), + unbinding: unbinding, + })), nil + + } + + historyMessages, err := w.makeChatFlowHistoryMessages(ctx, resolveAppID, conversationID, userID, messages[:len(req.GetAdditionalMessages())-1]) + if err != nil { + return nil, err + } + + if len(historyMessages) > 0 { + g := taskgroup.NewTaskGroup(ctx, len(historyMessages)) + for _, hm := range historyMessages { + hMsg := hm + g.Go(func() error { + _, err := messageClient.Create(ctx, hMsg) + if err != nil { + return err + } + return nil + }) + } + err = g.Wait() + if err != nil { + logs.CtxWarnf(ctx, "create history message failed, err=%v", err) + } + } + + userSchemaMessage, err := toSchemaMessage(lastUserMessage) + if err != nil { + return nil, err + } + + exeCfg := vo.ExecuteConfig{ + ID: mustParseInt64(req.GetWorkflowID()), + From: locator, + Version: version, + Operator: userID, + Mode: ternary.IFElse(isDebug, vo.ExecuteModeDebug, vo.ExecuteModeRelease), + AppID: appID, + AgentID: agentID, + ConnectorID: connectorID, + ConnectorUID: strconv.FormatInt(userID, 10), + TaskType: vo.TaskTypeForeground, + SyncPattern: vo.SyncPatternStream, + InputFailFast: true, + BizType: vo.BizTypeWorkflow, + ConversationID: ptr.Of(conversationID), + RoundID: ptr.Of(roundID), + UserMessage: userSchemaMessage, + Cancellable: isDebug == true, + } + + parameters["USER_INPUT"], err = w.makeChatFlowUserInput(ctx, lastUserMessage) + if err != nil { + return nil, err + } + + sr, err := GetWorkflowDomainSVC().StreamExecute(ctx, exeCfg, parameters) + if err != nil { + return nil, err + } + + return schema.StreamReaderWithConvert(sr, convertToChatFlowRunResponseList(ctx, convertToChatFlowInfo{ + appID: resolveAppID, + conversationID: conversationID, + roundID: roundID, + workflowID: mustParseInt64(req.GetWorkflowID()), + unbinding: unbinding, + })), nil + +} + +func (w *ApplicationService) makeChatFlowUserInput(ctx context.Context, message *workflow.EnterMessage) (string, error) { + type content struct { + Type string `json:"type,omitempty"` + FileID *string `json:"file_id"` + Text *string `json:"text"` + } + if message.ContentType == "text" { + return message.Content, nil + } else if message.ContentType == "object_string" { + contents := make([]content, 0) + err := sonic.UnmarshalString(message.Content, &contents) + if err != nil { + return "", err + } + texts := make([]string, 0) + urls := make([]string, 0) + for _, ct := range contents { + if ct.Text != nil && len(*ct.Text) > 0 { + texts = append(texts, *ct.Text) + } + if ct.FileID != nil && len(*ct.FileID) > 0 { + u, err := w.ImageX.GetResourceURL(ctx, *ct.FileID) + if err != nil { + return "", err + } + urls = append(urls, u.URL) + } + } + + return strings.Join(texts, ",") + strings.Join(urls, ","), nil + + } else { + return "", fmt.Errorf("invalid message ccontent type %v", message.ContentType) + } + +} +func (w *ApplicationService) makeChatFlowHistoryMessages(ctx context.Context, appID, conversationID int64, userID int64, messages []*workflow.EnterMessage) ([]*message.Message, error) { + + var ( + rID int64 + err error + ) + + historyMessages := make([]*message.Message, 0, len(messages)) + + for _, msg := range messages { + if msg.Role == userRole { + rID, err = w.IDGenerator.GenID(ctx) + if err != nil { + return nil, err + } + } else if msg.Role == assistantRole && rID == 0 { + continue + } else { + return nil, fmt.Errorf("invalid role type %v", msg.Role) + } + + m, err := toConversationMessage(ctx, appID, conversationID, userID, rID, ternary.IFElse(msg.Role == userRole, message.MessageTypeQuestion, message.MessageTypeAnswer), msg) + if err != nil { + return nil, err + } + + historyMessages = append(historyMessages, m) + + } + return historyMessages, nil +} + +func (w *ApplicationService) OpenAPICreateConversation(ctx context.Context, req *workflow.CreateConversationRequest) (resp *workflow.CreateConversationResponse, err error) { + + defer func() { + if panicErr := recover(); panicErr != nil { + err = safego.NewPanicErr(panicErr, debug.Stack()) + } + if err != nil { + err = vo.WrapIfNeeded(errno.ErrWorkflowOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error())) + } + }() + + var ( + appID = mustParseInt64(req.GetAppID()) + userID = ctxutil.MustGetUIDFromCtx(ctx) + env = ternary.IFElse(req.GetDraftMode(), vo.Draft, vo.Online) + cID int64 + //spaceID = mustParseInt64(req.GetSpaceID()) + //_ = spaceID + ) + + // todo check permission + + if !req.GetGetOrCreate() { + cID, err = GetWorkflowDomainSVC().UpdateConversation(ctx, env, appID, req.GetConnectorId(), userID, req.GetConversationMame()) + } else { + cID, err = GetWorkflowDomainSVC().GetOrCreateConversation(ctx, env, appID, req.GetConnectorId(), userID, req.GetConversationMame()) + } + if err != nil { + return nil, err + } + + return &workflow.CreateConversationResponse{ + ConversationData: &workflow.ConversationData{ + Id: cID, + }, + }, nil +} + +func toConversationMessage(_ context.Context, appID int64, cid int64, userID int64, roundID int64, messageType message.MessageType, msg *workflow.EnterMessage) (*message.Message, error) { + type content struct { + Type string `json:"type"` + FileID *string `json:"file_id"` + Text *string `json:"text"` + } + if msg.ContentType == "text" { + return &message.Message{ + Role: schema.User, + ConversationID: cid, + AgentID: appID, + RunID: roundID, + Content: msg.Content, + ContentType: message.ContentTypeText, + MessageType: messageType, + UserID: strconv.FormatInt(userID, 10), + }, nil + + } else if msg.ContentType == "object_string" { + contents := make([]*content, 0) + err := sonic.UnmarshalString(msg.Content, &contents) + if err != nil { + return nil, err + } + + m := &message.Message{ + Role: schema.User, + MessageType: messageType, + ConversationID: cid, + UserID: strconv.FormatInt(userID, 10), + RunID: roundID, + Content: msg.Content, + ContentType: message.ContentTypeMix, + MultiContent: make([]*message.InputMetaData, 0, len(contents)), + } + + for _, ct := range contents { + if ct.Text != nil { + m.MultiContent = append(m.MultiContent, &message.InputMetaData{ + Type: message.InputTypeText, + Text: *ct.Text, + }) + } else if ct.FileID != nil { + m.MultiContent = append(m.MultiContent, &message.InputMetaData{ + Type: message.InputType(ct.Type), + FileData: []*message.FileData{ + {Url: *ct.FileID}, + }, + }) + } else { + return nil, fmt.Errorf("invalid input type %v", ct.Type) + } + } + return m, nil + } else { + return nil, fmt.Errorf("invalid message content type %v", msg.ContentType) + } +} + +func toSchemaMessage(msg *workflow.EnterMessage) (*schema.Message, error) { + type content struct { + Type string `json:"type"` + FileID *string `json:"file_id"` + Text *string `json:"text"` + } + if msg.ContentType == "text" { + return &schema.Message{ + Role: schema.User, + Content: msg.Content, + }, nil + + } else if msg.ContentType == "object_string" { + contents := make([]*content, 0) + err := sonic.UnmarshalString(msg.Content, &contents) + if err != nil { + return nil, err + } + m := &schema.Message{ + Role: schema.User, + MultiContent: make([]schema.ChatMessagePart, 0, len(contents)), + } + + for _, ct := range contents { + if ct.Text != nil { + m.MultiContent = append(m.MultiContent, schema.ChatMessagePart{ + Type: schema.ChatMessagePartTypeText, + Text: *ct.Text, + }) + } else if ct.FileID != nil { + switch ct.Type { + case "file": + m.MultiContent = append(m.MultiContent, schema.ChatMessagePart{ + Type: schema.ChatMessagePartTypeFileURL, + Text: *ct.Text, + }) + case "image": + m.MultiContent = append(m.MultiContent, schema.ChatMessagePart{ + Type: schema.ChatMessagePartTypeImageURL, + Text: *ct.Text, + }) + case "audio": + m.MultiContent = append(m.MultiContent, schema.ChatMessagePart{ + Type: schema.ChatMessagePartTypeAudioURL, + Text: *ct.Text, + }) + case "video": + m.MultiContent = append(m.MultiContent, schema.ChatMessagePart{ + Type: schema.ChatMessagePartTypeVideoURL, + Text: *ct.Text, + }) + } + + } else { + return nil, fmt.Errorf("invalid input type %v", ct.Type) + } + } + return m, nil + } else { + return nil, fmt.Errorf("invalid message content type %v", msg.ContentType) + } +} + +type convertToChatFlowInfo struct { + appID int64 + conversationID int64 + roundID int64 + workflowID int64 + unbinding func() error +} + +func parserInput(inputString string) string { + result := map[string]any{} + lines := strings.Split(inputString, "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + keyValue := strings.SplitN(line, ":", 2) + if len(keyValue) == 2 { + result[keyValue[0]] = keyValue[1] + } + } + str, _ := sonic.MarshalString(result) + + return str + +} + +func convertToChatFlowRunResponseList(ctx context.Context, info convertToChatFlowInfo) func(msg *entity.Message) (responses []*workflow.ChatFlowRunResponse, err error) { + var ( + appID = info.appID + conversationID = info.conversationID + roundID = info.roundID + workflowID = info.workflowID + unbinding = info.unbinding + + spaceID int64 + executeID int64 + + hasFirstMessage = false + messageOutput string + messageID int64 + outputCount int32 + inputCount int32 + ) + var createOrUpdateMessage = func(msg string, role schema.RoleType, contentType message.ContentType) error { + entityMessage := &message.Message{ + AgentID: appID, + RunID: roundID, + Content: msg, + ConversationID: conversationID, + ContentType: contentType, + Role: role, + MessageType: message.MessageTypeAnswer, + } + if hasFirstMessage { + entityMessage.ID = messageID + _, err := crossmessage.DefaultSVC().Edit(ctx, entityMessage) + if err != nil { + return err + } + } else { + m, err := crossmessage.DefaultSVC().Create(ctx, entityMessage) + if err != nil { + return err + } + messageID = m.ID + hasFirstMessage = true + } + return nil + + } + + return func(msg *entity.Message) (responses []*workflow.ChatFlowRunResponse, err error) { + if msg.StateMessage != nil { + if executeID > 0 && executeID != msg.StateMessage.ExecuteID { + return nil, schema.ErrNoValue + } + switch msg.StateMessage.Status { + case entity.WorkflowSuccess: + chatDoneEvent := &vo.ChatFlowDetail{ + ID: strconv.FormatInt(roundID, 10), + ConversationID: strconv.FormatInt(conversationID, 10), + BotID: strconv.FormatInt(appID, 10), + Status: vo.Completed, + ExecuteID: strconv.FormatInt(executeID, 10), + Usage: &vo.Usage{ + InputTokens: ptr.Of(inputCount), + OutputTokens: ptr.Of(outputCount), + TokenCount: ptr.Of(outputCount + inputCount), + }, + } + data, err := sonic.MarshalString(chatDoneEvent) + if err != nil { + return nil, err + } + + doneData, err := sonic.MarshalString(map[string]interface{}{ + "debug_url": fmt.Sprintf(vo.DebugURLTpl, executeID, spaceID, workflowID), + }) + if err != nil { + return nil, err + } + if unbinding != nil { + uErr := unbinding() + if uErr != nil { + return nil, uErr + } + } + return []*workflow.ChatFlowRunResponse{ + { + Event: string(vo.ChatFlowCompleted), + Data: data, + }, + { + Event: string(vo.ChatFlowDone), + Data: doneData, + }, + }, err + case entity.WorkflowFailed: + var wfe vo.WorkflowError + if !errors.As(msg.StateMessage.LastError, &wfe) { + panic("stream run last error is not a WorkflowError") + } + + chatFailedEvent := &vo.ErrorDetail{ + Code: strconv.Itoa(int(wfe.Code())), + Msg: wfe.Msg(), + DebugUrl: wfe.DebugURL(), + } + data, err := sonic.MarshalString(chatFailedEvent) + if err != nil { + return nil, err + } + + if unbinding() != nil { + uErr := unbinding() + if uErr != nil { + return nil, uErr + } + } + + return []*workflow.ChatFlowRunResponse{ + { + Event: string(vo.ChatFlowError), + Data: data, + }, + }, err + + case entity.WorkflowCancel: + if unbinding() != nil { + uErr := unbinding() + if uErr != nil { + return nil, uErr + } + } + + case entity.WorkflowInterrupted: + chatEvent := &vo.ChatFlowDetail{ + ID: strconv.FormatInt(roundID, 10), + ConversationID: strconv.FormatInt(conversationID, 10), + Status: vo.RequiresAction, + ExecuteID: strconv.FormatInt(executeID, 10), + } + data, err := sonic.MarshalString(chatEvent) + if err != nil { + return nil, err + } + + doneData, err := sonic.MarshalString(map[string]interface{}{ + "debug_url": fmt.Sprintf(vo.DebugURLTpl, executeID, spaceID, workflowID), + }) + if err != nil { + return nil, err + } + + responses = append(responses, &workflow.ChatFlowRunResponse{ + Event: string(vo.ChatFlowRequiresAction), + Data: data, + }) + + responses = append(responses, &workflow.ChatFlowRunResponse{ + Event: string(vo.ChatFlowDone), + Data: doneData, + }) + err = GetWorkflowDomainSVC().BindConvRelatedInfo(ctx, conversationID, entity.ConvRelatedInfo{ + EventID: msg.StateMessage.InterruptEvent.ID, ExecID: executeID, NodeType: msg.StateMessage.InterruptEvent.NodeType, + }) + if err != nil { + return nil, err + } + + return responses, nil + + case entity.WorkflowRunning: + executeID = msg.StateMessage.ExecuteID + spaceID = msg.StateMessage.SpaceID + + responses = make([]*workflow.ChatFlowRunResponse, 0) + chatEvent := &vo.ChatFlowDetail{ + ID: strconv.FormatInt(roundID, 10), + ConversationID: strconv.FormatInt(conversationID, 10), + Status: vo.Created, + ExecuteID: strconv.FormatInt(executeID, 10), + } + data, err := sonic.MarshalString(chatEvent) + if err != nil { + return nil, err + } + responses = append(responses, &workflow.ChatFlowRunResponse{ + Event: string(vo.ChatFlowCreated), + Data: data, + }) + + chatEvent.Status = vo.InProgress + data, err = sonic.MarshalString(chatEvent) + if err != nil { + return nil, err + } + + responses = append(responses, &workflow.ChatFlowRunResponse{ + Event: string(vo.ChatFlowInProgress), + Data: data, + }) + return responses, nil + + default: + return nil, schema.ErrNoValue + } + } + if msg.DataMessage != nil { + if msg.Type != entity.Answer { + return nil, schema.ErrNoValue + } + // stream run will skip all messages from workflow tools + if executeID > 0 && executeID != msg.DataMessage.ExecuteID { + return nil, schema.ErrNoValue + } + + dataMessage := msg.DataMessage + if dataMessage.Usage != nil { + inputCount += int32(msg.DataMessage.Usage.InputTokens) + outputCount += int32(msg.DataMessage.Usage.OutputTokens) + } + + var ( + contentType message.ContentType + messageEvent = &vo.MessageDetail{ + ChatID: strconv.FormatInt(roundID, 10), + ConversationID: strconv.FormatInt(conversationID, 10), + BotID: strconv.FormatInt(appID, 10), + Role: string(dataMessage.Role), + Type: string(dataMessage.Type), + } + ) + switch msg.DataMessage.NodeType { + case entity.NodeTypeInputReceiver: + msg.Content, err = renderInputCardDSL(msg.Content) + if err != nil { + return nil, err + } + messageEvent.Content = msg.Content + messageEvent.ContentType = string(message.ContentTypeCard) + contentType = message.ContentTypeCard + case entity.NodeTypeQuestionAnswer: + msg.Content, err = renderSelectOptionCardDSL(msg.Content) + if err != nil { + return nil, err + } + messageEvent.Content = msg.Content + messageEvent.ContentType = string(message.ContentTypeCard) + contentType = message.ContentTypeCard + default: + contentType = message.ContentTypeText + messageEvent.Content = msg.Content + messageEvent.ContentType = string(message.ContentTypeText) + } + + messageOutput += msg.Content + err = createOrUpdateMessage(messageOutput, dataMessage.Role, contentType) + if err != nil { + return nil, err + } + + messageEvent.ID = strconv.FormatInt(messageID, 10) + data, err := sonic.MarshalString(messageEvent) + if err != nil { + return nil, err + } + + return []*workflow.ChatFlowRunResponse{ + { + Event: ternary.IFElse(msg.Last, string(vo.ChatFlowMessageCompleted), string(vo.ChatFlowMessageDelta)), + Data: data, + }, + }, nil + + } + + return nil, err + } +} + +func renderInputCardDSL(c string) (string, error) { + type contentInfo struct { + Content string `json:"content"` + } + type field struct { + Type string `json:"type"` + Name string `json:"name"` + Required bool `json:"required"` + } + type inputCard struct { + CardType int64 `json:"card_type"` + ContentType int64 `json:"content_type"` + ResponseType string `json:"response_type"` + TemplateId int64 `json:"template_id"` + TemplateURL string `json:"template_url"` + Data string `json:"data"` + XProperties map[string]string `json:"x_properties"` + } + + info := &contentInfo{} + err := sonic.UnmarshalString(c, info) + if err != nil { + return "", err + } + + fields := make([]*field, 0) + _ = sonic.UnmarshalString(info.Content, &fields) + iCard := defaultCard() + iCard.Variables["5fJt3qKpSz"].(map[string]any)["defaultValue"] = fields + iCardString, _ := sonic.MarshalString(iCard) + + rCard := &inputCard{ + CardType: 3, + ContentType: 50, + ResponseType: "card", + TemplateId: 7383997384420262000, + TemplateURL: "", + Data: iCardString, + } + + type props struct { + CardType string `json:"card_type"` + InputCardData []*field `json:"input_card_data"` + } + + propsString, _ := sonic.MarshalString(props{ + CardType: "INPUT", + InputCardData: fields, + }) + + rCard.XProperties = map[string]string{ + "workflow_card_info": propsString, + } + rCardString, _ := sonic.MarshalString(rCard) + + return rCardString, nil + +} + +func renderSelectOptionCardDSL(c string) (string, error) { + type contentInfo struct { + Messages []struct { + Content struct { + Options []struct { + Name string `json:"name"` + } `json:"options"` + } `json:"content"` + } `json:"messages"` + Question string `json:"question"` + } + + type field struct { + Name string `json:"name"` + } + type key struct { + Key string `json:"key"` + } + + type inputCard struct { + CardType int64 `json:"card_type"` + ContentType int64 `json:"content_type"` + ResponseType string `json:"response_type"` + TemplateId int64 `json:"template_id"` + TemplateURL string `json:"template_url"` + Data string `json:"data"` + XProperties map[string]string `json:"x_properties"` + } + + info := &contentInfo{} + err := sonic.UnmarshalString(c, info) + if err != nil { + return "", err + } + + iCard := defaultCard() + + keys := make([]*key, 0) + fields := make([]*field, 0) + for _, msg := range info.Messages { + for _, op := range msg.Content.Options { + keys = append(keys, &key{Key: op.Name}) + fields = append(fields, &field{Name: op.Name}) + } + } + + iCard.Variables["5fJt3qKpSz"].(map[string]any)["defaultValue"] = map[string]any{ + "description": info.Question, + "list": keys, + } + iCardString, _ := sonic.MarshalString(iCard) + + rCard := &inputCard{ + CardType: 3, + ContentType: 50, + ResponseType: "card", + TemplateId: 7383997384420262000, + TemplateURL: "", + Data: iCardString, + } + + type props struct { + CardType string `json:"card_type"` + QuestionCardData struct { + Title string `json:"Title"` + Options []*field `json:"Options"` + } `json:"question_card_data"` + } + + propsString, _ := sonic.MarshalString(props{ + CardType: "QUESTION", + QuestionCardData: struct { + Title string `json:"Title"` + Options []*field `json:"Options"` + }{Title: info.Question, Options: fields}, + }) + + rCard.XProperties = map[string]string{ + "workflow_card_info": propsString, + } + rCardString, _ := sonic.MarshalString(rCard) + + return rCardString, nil + +} diff --git a/backend/application/workflow/workflow.go b/backend/application/workflow/workflow.go index ae5486e70..05b0bffcc 100644 --- a/backend/application/workflow/workflow.go +++ b/backend/application/workflow/workflow.go @@ -255,9 +255,10 @@ func (w *ApplicationService) UpdateWorkflowMeta(ctx context.Context, req *workfl } err = GetWorkflowDomainSVC().UpdateMeta(ctx, mustParseInt64(req.GetWorkflowID()), &vo.MetaUpdate{ - Name: req.Name, - Desc: req.Desc, - IconURI: req.IconURI, + Name: req.Name, + Desc: req.Desc, + IconURI: req.IconURI, + WorkflowMode: req.FlowMode, }) if err != nil { return nil, err @@ -4027,3 +4028,62 @@ func (w *ApplicationService) convertChatFlowRole(ctx context.Context, role *enti return res, nil } + +func (w *ApplicationService) OpenAPIGetWorkflowInfo(ctx context.Context, req *workflow.OpenAPIGetWorkflowInfoRequest) ( + _ *workflow.OpenAPIGetWorkflowInfoResponse, err error) { + defer func() { + if panicErr := recover(); panicErr != nil { + err = safego.NewPanicErr(panicErr, debug.Stack()) + } + + if err != nil { + err = vo.WrapIfNeeded(errno.ErrChatFlowRoleOperationFail, err, errorx.KV("cause", vo.UnwrapRootErr(err).Error())) + } + }() + + uID := ctxutil.MustGetUIDFromCtx(ctx) + wf, err := GetWorkflowDomainSVC().Get(ctx, &vo.GetPolicy{ + ID: mustParseInt64(req.GetWorkflowID()), + MetaOnly: true, + }) + if err != nil { + return nil, err + } + if err = checkUserSpace(ctx, uID, wf.Meta.SpaceID); err != nil { + return nil, err + } + + if !IsChatFlow(wf) { + logs.CtxWarnf(ctx, "GetChatFlowRole not chat flow, workflowID: %d", wf.ID) + return nil, vo.WrapError(errno.ErrChatFlowRoleOperationFail, fmt.Errorf("workflow %d is not a chat flow", wf.ID)) + } + + var version string + if wf.Meta.AppID != nil { + version = "" // TODO : search version from DB using AppID + } + + role, err := GetWorkflowDomainSVC().GetChatFlowRole(ctx, mustParseInt64(req.WorkflowID), version) + if err != nil { + return nil, err + } + + if role == nil { + logs.CtxWarnf(ctx, "GetChatFlowRole role nil, workflowID: %d", wf.ID) + // Return nil for the error to align with the production behavior, + // where the GET API may be called before the CREATE API during chatflow creation. + return &workflow.OpenAPIGetWorkflowInfoResponse{}, nil + } + + wfRole, err := w.convertChatFlowRole(ctx, role) + + if err != nil { + return nil, fmt.Errorf("failed to get chat flow role config, internal data processing error: %+v", err) + } + + return &workflow.OpenAPIGetWorkflowInfoResponse{ + WorkflowInfo: &workflow.WorkflowInfo{ + Role: wfRole, + }, + }, nil +} diff --git a/backend/conf/plugin/pluginproduct/plugin_meta.yaml b/backend/conf/plugin/pluginproduct/plugin_meta.yaml index 2674dac58..20cec755c 100644 --- a/backend/conf/plugin/pluginproduct/plugin_meta.yaml +++ b/backend/conf/plugin/pluginproduct/plugin_meta.yaml @@ -906,4 +906,4 @@ - tool_id: 220009 deprecated: false method: get - sub_url: /v5/place/around \ No newline at end of file + sub_url: /v5/place/around diff --git a/backend/crossdomain/workflow/conversation/conversation.go b/backend/crossdomain/workflow/conversation/conversation.go index 3c6c3ee2e..cf1ee0858 100644 --- a/backend/crossdomain/workflow/conversation/conversation.go +++ b/backend/crossdomain/workflow/conversation/conversation.go @@ -181,7 +181,7 @@ func convertMessage(msgs []*msgentity.Message) ([]*conversation.Message, error) for _, fd := range c.FileData { mcs = append(mcs, &conversation.Content{ Type: string(c.Type), - Uri: ptr.Of(fd.Url), + Uri: ptr.Of(fd.URI), }) } } else { diff --git a/backend/domain/workflow/component_interface.go b/backend/domain/workflow/component_interface.go index ee054f2f7..6b858aacd 100644 --- a/backend/domain/workflow/component_interface.go +++ b/backend/domain/workflow/component_interface.go @@ -32,7 +32,9 @@ type Executable interface { AsyncExecute(ctx context.Context, config vo.ExecuteConfig, input map[string]any) (int64, error) AsyncExecuteNode(ctx context.Context, nodeID string, config vo.ExecuteConfig, input map[string]any) (int64, error) AsyncResume(ctx context.Context, req *entity.ResumeRequest, config vo.ExecuteConfig) error + StreamExecute(ctx context.Context, config vo.ExecuteConfig, input map[string]any) (*schema.StreamReader[*entity.Message], error) + StreamResume(ctx context.Context, req *entity.ResumeRequest, config vo.ExecuteConfig) ( *schema.StreamReader[*entity.Message], error) @@ -65,6 +67,8 @@ type ConversationService interface { 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, error) + UpdateConversation(ctx context.Context, env vo.Env, appID, connectorID, userID int64, conversationName string) (int64, error) } type InterruptEventStore interface { @@ -73,6 +77,9 @@ type InterruptEventStore interface { 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 { @@ -122,4 +129,6 @@ type ConversationRepository interface { 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 } diff --git a/backend/domain/workflow/entity/interrupt_event.go b/backend/domain/workflow/entity/interrupt_event.go index 39734fb83..96ca6110a 100644 --- a/backend/domain/workflow/entity/interrupt_event.go +++ b/backend/domain/workflow/entity/interrupt_event.go @@ -72,3 +72,9 @@ type ToolInterruptEvent struct { ExecuteID int64 *InterruptEvent } + +type ConvRelatedInfo struct { + EventID int64 + ExecID int64 + NodeType NodeType +} diff --git a/backend/domain/workflow/entity/vo/chatflow.go b/backend/domain/workflow/entity/vo/chatflow.go new file mode 100644 index 000000000..9f5bacb2d --- /dev/null +++ b/backend/domain/workflow/entity/vo/chatflow.go @@ -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 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"` +} + +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"` +} + +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"` +} diff --git a/backend/domain/workflow/entity/vo/execution.go b/backend/domain/workflow/entity/vo/execution.go index c50343754..4b7e843a8 100644 --- a/backend/domain/workflow/entity/vo/execution.go +++ b/backend/domain/workflow/entity/vo/execution.go @@ -16,7 +16,10 @@ package vo -import "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow" +import ( + "github.com/cloudwego/eino/schema" + "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow" +) type ExecuteConfig struct { ID int64 @@ -37,6 +40,7 @@ type ExecuteConfig struct { WorkflowMode WorkflowMode RoundID *int64 // if workflow is chat flow, conversation round id is required ConversationID *int64 // if workflow is chat flow, conversation id is required + UserMessage *schema.Message } type ExecuteMode string diff --git a/backend/domain/workflow/entity/vo/meta.go b/backend/domain/workflow/entity/vo/meta.go index c7ce1d36a..4bdb58780 100644 --- a/backend/domain/workflow/entity/vo/meta.go +++ b/backend/domain/workflow/entity/vo/meta.go @@ -68,6 +68,7 @@ type MetaUpdate struct { IconURI *string HasPublished *bool LatestPublishedVersion *string + WorkflowMode *Mode } type MetaQuery struct { diff --git a/backend/domain/workflow/interface.go b/backend/domain/workflow/interface.go index e5afe1072..d21414751 100644 --- a/backend/domain/workflow/interface.go +++ b/backend/domain/workflow/interface.go @@ -65,6 +65,8 @@ type Service interface { SyncRelatedWorkflowResources(ctx context.Context, appID int64, relatedWorkflows map[int64]entity.IDVersionPair, related vo.ExternalResourceRelated) error ConversationService + BindConvRelatedInfo(ctx context.Context, convID int64, info entity.ConvRelatedInfo) error + GetConvRelatedInfo(ctx context.Context, convID int64) (*entity.ConvRelatedInfo, bool, func() error, error) } type Repository interface { diff --git a/backend/domain/workflow/internal/compose/state.go b/backend/domain/workflow/internal/compose/state.go index a70476b47..954b9e9ef 100644 --- a/backend/domain/workflow/internal/compose/state.go +++ b/backend/domain/workflow/internal/compose/state.go @@ -87,6 +87,7 @@ func init() { _ = compose.RegisterSerializableType[vo.BizType]("biz_type") _ = compose.RegisterSerializableType[*execute.AppVariables]("app_variables") _ = compose.RegisterSerializableType[workflow2.WorkflowMode]("workflow_mode") + _ = compose.RegisterSerializableType[*schema.Message]("schema_message") } diff --git a/backend/domain/workflow/internal/repo/conversation_repository.go b/backend/domain/workflow/internal/repo/conversation_repository.go index b46982473..8db035d93 100644 --- a/backend/domain/workflow/internal/repo/conversation_repository.go +++ b/backend/domain/workflow/internal/repo/conversation_repository.go @@ -724,3 +724,60 @@ func (r *RepositoryImpl) UpdateDynamicConversationNameByID(ctx context.Context, } } + +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) + } + +} diff --git a/backend/domain/workflow/internal/repo/interrupt_event_store.go b/backend/domain/workflow/internal/repo/interrupt_event_store.go index 31d855df2..89f423787 100644 --- a/backend/domain/workflow/internal/repo/interrupt_event_store.go +++ b/backend/domain/workflow/internal/repo/interrupt_event_store.go @@ -20,6 +20,7 @@ import ( "context" "errors" "fmt" + "github.com/redis/go-redis/v9" "time" "github.com/coze-dev/coze-studio/backend/domain/workflow/entity" @@ -38,6 +39,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 +248,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 +} diff --git a/backend/domain/workflow/internal/repo/repository.go b/backend/domain/workflow/internal/repo/repository.go index f4497afd4..98673f6a6 100644 --- a/backend/domain/workflow/internal/repo/repository.go +++ b/backend/domain/workflow/internal/repo/repository.go @@ -500,6 +500,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 } diff --git a/backend/domain/workflow/service/conversation_impl.go b/backend/domain/workflow/service/conversation_impl.go index 00443a45a..9937f083b 100644 --- a/backend/domain/workflow/service/conversation_impl.go +++ b/backend/domain/workflow/service/conversation_impl.go @@ -22,6 +22,7 @@ import ( cloudworkflow "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow" "github.com/coze-dev/coze-studio/backend/domain/workflow" + "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/conversation" "github.com/coze-dev/coze-studio/backend/domain/workflow/entity" "github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo" "github.com/coze-dev/coze-studio/backend/pkg/errorx" @@ -335,3 +336,91 @@ func (c *conversationImpl) replaceWorkflowsConversationName(ctx context.Context, 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, 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 + } + + conversationIDGenerator := workflow.ConversationIDGenerator(func(ctx context.Context, appID int64, userID, connectorID int64) (int64, error) { + return conversation.GetConversationManager().CreateConversation(ctx, &conversation.CreateConversationRequest{ + AppID: appID, + UserID: userID, + ConnectorID: connectorID, + }) + }) + + if existed { + conversationID, _, err := c.repo.GetOrCreateStaticConversation(ctx, env, conversationIDGenerator, &vo.CreateStaticConversation{ + AppID: appID, + ConnectorID: connectorID, + UserID: userID, + TemplateID: t.TemplateID, + }) + if err != nil { + return 0, err + } + return conversationID, nil + } + + conversationID, _, err := c.repo.GetOrCreateDynamicConversation(ctx, env, conversationIDGenerator, &vo.CreateDynamicConversation{ + AppID: appID, + ConnectorID: connectorID, + UserID: userID, + Name: conversationName, + }) + if err != nil { + return 0, err + } + return conversationID, 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 { + newConversationID, err := conversation.GetConversationManager().CreateConversation(ctx, &conversation.CreateConversationRequest{ + AppID: appID, + UserID: userID, + ConnectorID: connectorID, + }) + err = c.repo.UpdateStaticConversation(ctx, env, t.TemplateID, connectorID, userID, newConversationID) + if err != nil { + return 0, err + } + return newConversationID, 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) + } + + newConversationID, err := conversation.GetConversationManager().CreateConversation(ctx, &conversation.CreateConversationRequest{ + AppID: appID, + UserID: userID, + ConnectorID: connectorID, + }) + err = c.repo.UpdateDynamicConversation(ctx, env, dy.ConversationID, newConversationID) + if err != nil { + return 0, err + } + return newConversationID, nil + +} diff --git a/backend/domain/workflow/service/executable_impl.go b/backend/domain/workflow/service/executable_impl.go index f5a97a3fd..d37ac4ceb 100644 --- a/backend/domain/workflow/service/executable_impl.go +++ b/backend/domain/workflow/service/executable_impl.go @@ -380,6 +380,8 @@ func (i *impl) StreamExecute(ctx context.Context, config vo.ExecuteConfig, input return nil, err } + config.WorkflowMode = wfEntity.Mode + isApplicationWorkflow := wfEntity.AppID != nil if isApplicationWorkflow && config.Mode == vo.ExecuteModeRelease { err = i.checkApplicationWorkflowReleaseVersion(ctx, *wfEntity.AppID, config.ConnectorID, config.ID, config.Version) diff --git a/backend/domain/workflow/service/service_impl.go b/backend/domain/workflow/service/service_impl.go index 8c25a5755..edc07f468 100644 --- a/backend/domain/workflow/service/service_impl.go +++ b/backend/domain/workflow/service/service_impl.go @@ -851,6 +851,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 + } + } + err = search.GetNotifier().PublishWorkflowResource(ctx, search.Updated, &search.Resource{ WorkflowID: id, URI: metaUpdate.IconURI, @@ -1822,6 +1829,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 @@ -2009,3 +2024,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: vo.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) +} diff --git a/idl/workflow/workflow.thrift b/idl/workflow/workflow.thrift index 7c4860a94..2f207d402 100644 --- a/idl/workflow/workflow.thrift +++ b/idl/workflow/workflow.thrift @@ -2200,3 +2200,34 @@ struct OpenAPIGetWorkflowInfoResponse{ 255: required base.BaseResp BaseResp } + +struct CreateConversationRequest { + 1: optional map MetaData (api.body = "meta_data") //自定义透传字段 + 3: optional i64 BotId (api.body = "bot_id", api.js_conv="true") + 4: optional i64 ConnectorId (api.body= "connector_id", api.js_conv="true") + 5: optional string SpaceID (api.body= "space_id", api.js_conv="true") + 9 : optional string AppID (go.tag="json:\"app_id\"") + 10: optional string WorkflowID (go.tag="json:\"workflow_id\"") + 11: optional string ConversationMame (go.tag="json:\"conversation_name\"") + 12: optional bool GetOrCreate (go.tag="json:\"get_or_create\"") + 13: optional bool DraftMode (go.tag="json:\"draft_mode\"") + 255: optional base.Base Base +} + + +struct CreateConversationResponse { + 1: i64 code + 2: string msg + 3: optional ConversationData ConversationData (api.body = "data") +} + + +struct ConversationData { + 1: i64 Id (api.body = "id", agw.key = "id", api.js_conv="true") + 2: i64 CreatedAt (api.body = "created_at", agw.key = "created_at") + 3: map MetaData (api.body = "meta_data", agw.key = "meta_data") + 4: optional i64 CreatorID (api.body = "creator_d", agw.key = "creator_d", api.js_conv="true") + 5: optional i64 ConnectorID (api.body = "connector_id", agw.key="connector_id", api.js_conv="true") + 6: optional i64 LastSectionID (api.body="last_section_id", api.js_conv="true") + 7: optional i64 AccountID (api.body = "account_id") +} diff --git a/idl/workflow/workflow_svc.thrift b/idl/workflow/workflow_svc.thrift index a20312d61..7476885da 100644 --- a/idl/workflow/workflow_svc.thrift +++ b/idl/workflow/workflow_svc.thrift @@ -66,6 +66,7 @@ service WorkflowService { workflow.CreateChatFlowRoleResponse CreateChatFlowRole(1: workflow.CreateChatFlowRoleRequest request) (api.post='/api/workflow_api/chat_flow_role/create', api.category="workflow_api", api.gen_path="workflow_api", agw.preserve_base = "true") workflow.DeleteChatFlowRoleResponse DeleteChatFlowRole(1: workflow.DeleteChatFlowRoleRequest request) (api.post='/api/workflow_api/chat_flow_role/delete', api.category="workflow_api", api.gen_path="workflow_api", agw.preserve_base = "true") // App Release Management + // App 发布管理 workflow.ListPublishWorkflowResponse ListPublishWorkflow(1: workflow.ListPublishWorkflowRequest request) (api.post='/api/workflow_api/list_publish_workflow', api.category="workflow_api", api.gen_path="workflow_api", agw.preserve_base = "true") // Open API @@ -75,4 +76,7 @@ service WorkflowService { workflow.GetWorkflowRunHistoryResponse OpenAPIGetWorkflowRunHistory(1:workflow.GetWorkflowRunHistoryRequest request)(api.get='/v1/workflow/get_run_history', api.category="workflow_open_api", api.tag="openapi", api.gen_path="workflow_api", agw.preserve_base = "false") workflow.ChatFlowRunResponse OpenAPIChatFlowRun(1: workflow.ChatFlowRunRequest request)(api.post = "/v1/workflows/chat", api.category="workflow_open_api", api.tag="openapi", api.gen_path="workflow_open_api") workflow.OpenAPIGetWorkflowInfoResponse OpenAPIGetWorkflowInfo(1: workflow.OpenAPIGetWorkflowInfoRequest request)(api.get = "/v1/workflows/:workflow_id", api.category="workflow_open_api", api.tag="openapi", api.gen_path="workflow_open_api") + + workflow.CreateConversationRequest OpenAPICreateConversation(1: workflow.CreateConversationRequest request)(api.post = "/v1/workflow/conversation/create", api.category="workflow_open_api",api.tag="openapi", api.gen_path="workflow_open_api", agw.preserve_base = "true") + } diff --git a/scripts/setup/python.sh b/scripts/setup/python.sh old mode 100755 new mode 100644 index 38a677c2b..8d82a982f --- a/scripts/setup/python.sh +++ b/scripts/setup/python.sh @@ -1,4 +1,20 @@ #!/usr/bin/env bash +# +# 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. +# + SETUP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(dirname "$SETUP_DIR")" @@ -64,4 +80,4 @@ if [ -f "$WORKFLOW_SANBOX" ]; then else echo "❌ $WORKFLOW_SANBOX file not found" exit 1 -fi \ No newline at end of file +fi