From efa20f22f62ad6ab6b8cb6dbeb04577a1474cc95 Mon Sep 17 00:00:00 2001 From: mrh997 Date: Wed, 30 Jul 2025 13:35:22 +0800 Subject: [PATCH] fix(plugin): update tool may reset request or response parameters (#302) --- backend/application/base/pluginutil/api.go | 17 ++++--- backend/application/plugin/plugin.go | 2 +- .../plugin/internal/dal/plugin_draft.go | 13 +++-- .../domain/plugin/repository/plugin_impl.go | 8 +++ .../plugin/repository/plugin_repository.go | 1 + backend/domain/plugin/repository/tool_impl.go | 39 -------------- .../plugin/repository/tool_repository.go | 3 -- backend/domain/plugin/service/plugin_draft.go | 51 ++++++++++++++----- backend/domain/plugin/service/service.go | 4 +- .../internal/mock/domain/plugin/interface.go | 2 +- 10 files changed, 69 insertions(+), 71 deletions(-) diff --git a/backend/application/base/pluginutil/api.go b/backend/application/base/pluginutil/api.go index 79b42e80..fc8fbb22 100644 --- a/backend/application/base/pluginutil/api.go +++ b/backend/application/base/pluginutil/api.go @@ -88,6 +88,15 @@ func APIParamsToOpenapiOperation(reqParams, respParams []*common.APIParameter) ( } } + if reqParams != nil { + if !hasSetParams { + op.Parameters = []*openapi3.ParameterRef{} + } + if !hasSetReqBody { + op.RequestBody = entity.DefaultOpenapi3RequestBody() + } + } + hasSetRespBody := false for _, apiParam := range respParams { @@ -127,13 +136,7 @@ func APIParamsToOpenapiOperation(reqParams, respParams []*common.APIParameter) ( } } - if op.Parameters == nil { - op.Parameters = []*openapi3.ParameterRef{} - } - if op.RequestBody == nil { - op.RequestBody = entity.DefaultOpenapi3RequestBody() - } - if op.Responses == nil { + if respParams != nil && !hasSetRespBody { op.Responses = entity.DefaultOpenapi3Responses() } diff --git a/backend/application/plugin/plugin.go b/backend/application/plugin/plugin.go index 8682d29e..25c8da05 100644 --- a/backend/application/plugin/plugin.go +++ b/backend/application/plugin/plugin.go @@ -822,7 +822,7 @@ func (p *PluginApplicationService) UpdateAPI(ctx context.Context, req *pluginAPI method = &m } - updateReq := &service.UpdateToolDraftRequest{ + updateReq := &service.UpdateDraftToolRequest{ PluginID: req.PluginID, ToolID: req.APIID, Name: req.Name, diff --git a/backend/domain/plugin/internal/dal/plugin_draft.go b/backend/domain/plugin/internal/dal/plugin_draft.go index 53ad06ab..c4341b95 100644 --- a/backend/domain/plugin/internal/dal/plugin_draft.go +++ b/backend/domain/plugin/internal/dal/plugin_draft.go @@ -25,7 +25,7 @@ import ( "gorm.io/gen/field" "gorm.io/gorm" - "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin" + pluginModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin" "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common" "github.com/coze-dev/coze-studio/backend/domain/plugin/conf" "github.com/coze-dev/coze-studio/backend/domain/plugin/entity" @@ -50,7 +50,7 @@ type PluginDraftDAO struct { type pluginDraftPO model.PluginDraft func (p pluginDraftPO) ToDO() *entity.PluginInfo { - return entity.NewPluginInfo(&plugin.PluginInfo{ + return entity.NewPluginInfo(&pluginModel.PluginInfo{ ID: p.ID, SpaceID: p.SpaceID, DeveloperID: p.DeveloperID, @@ -257,9 +257,12 @@ func (p *PluginDraftDAO) List(ctx context.Context, spaceID, appID int64, pageInf } func (p *PluginDraftDAO) Update(ctx context.Context, plugin *entity.PluginInfo) (err error) { - mf, err := plugin.Manifest.EncryptAuthPayload() - if err != nil { - return fmt.Errorf("EncryptAuthPayload failed, err=%w", err) + var mf *pluginModel.PluginManifest + if plugin.Manifest != nil { + mf, err = plugin.Manifest.EncryptAuthPayload() + if err != nil { + return fmt.Errorf("EncryptAuthPayload failed, err=%w", err) + } } m := &model.PluginDraft{ diff --git a/backend/domain/plugin/repository/plugin_impl.go b/backend/domain/plugin/repository/plugin_impl.go index 362c03ce..1b67cff8 100644 --- a/backend/domain/plugin/repository/plugin_impl.go +++ b/backend/domain/plugin/repository/plugin_impl.go @@ -853,3 +853,11 @@ func (p *pluginRepoImpl) MoveAPPPluginToLibrary(ctx context.Context, draftPlugin return nil } + +func (p *pluginRepoImpl) UpdateDebugExample(ctx context.Context, pluginID int64, openapiDoc *model.Openapi3T) (err error) { + updatedPlugin := entity.NewPluginInfo(&model.PluginInfo{ + ID: pluginID, + OpenapiDoc: openapiDoc, + }) + return p.pluginDraftDAO.Update(ctx, updatedPlugin) +} diff --git a/backend/domain/plugin/repository/plugin_repository.go b/backend/domain/plugin/repository/plugin_repository.go index 5adff49c..56e52d4b 100644 --- a/backend/domain/plugin/repository/plugin_repository.go +++ b/backend/domain/plugin/repository/plugin_repository.go @@ -35,6 +35,7 @@ type PluginRepository interface { UpdateDraftPluginWithCode(ctx context.Context, req *UpdatePluginDraftWithCode) (err error) DeleteDraftPlugin(ctx context.Context, pluginID int64) (err error) DeleteAPPAllPlugins(ctx context.Context, appID int64) (pluginIDs []int64, err error) + UpdateDebugExample(ctx context.Context, pluginID int64, openapiDoc *plugin.Openapi3T) (err error) GetOnlinePlugin(ctx context.Context, pluginID int64, opts ...PluginSelectedOptions) (plugin *entity.PluginInfo, exist bool, err error) MGetOnlinePlugins(ctx context.Context, pluginIDs []int64, opts ...PluginSelectedOptions) (plugins []*entity.PluginInfo, err error) diff --git a/backend/domain/plugin/repository/tool_impl.go b/backend/domain/plugin/repository/tool_impl.go index 9ac111cc..f75d7a7a 100644 --- a/backend/domain/plugin/repository/tool_impl.go +++ b/backend/domain/plugin/repository/tool_impl.go @@ -23,7 +23,6 @@ import ( "gorm.io/gorm" - "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin" pluginConf "github.com/coze-dev/coze-studio/backend/domain/plugin/conf" "github.com/coze-dev/coze-studio/backend/domain/plugin/entity" "github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal" @@ -389,41 +388,3 @@ func (t *toolRepoImpl) MGetVersionAgentTool(ctx context.Context, agentID int64, func (t *toolRepoImpl) BatchCreateVersionAgentTools(ctx context.Context, agentID int64, agentVersion string, tools []*entity.ToolInfo) (err error) { return t.agentToolVersionDAO.BatchCreate(ctx, agentID, agentVersion, tools) } - -func (t *toolRepoImpl) UpdateDraftToolAndDebugExample(ctx context.Context, pluginID int64, doc *plugin.Openapi3T, updatedTool *entity.ToolInfo) (err error) { - tx := t.query.Begin() - if tx.Error != nil { - return tx.Error - } - - defer func() { - if r := recover(); r != nil { - if e := tx.Rollback(); e != nil { - logs.CtxErrorf(ctx, "rollback failed, err=%v", e) - } - err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack())) - return - } - if err != nil { - if e := tx.Rollback(); e != nil { - logs.CtxErrorf(ctx, "rollback failed, err=%v", e) - } - } - }() - - err = t.toolDraftDAO.UpdateWithTX(ctx, tx, updatedTool) - if err != nil { - return err - } - - updatedPlugin := entity.NewPluginInfo(&plugin.PluginInfo{ - ID: pluginID, - OpenapiDoc: doc, - }) - err = t.pluginDraftDAO.UpdateWithTX(ctx, tx, updatedPlugin) - if err != nil { - return err - } - - return tx.Commit() -} diff --git a/backend/domain/plugin/repository/tool_repository.go b/backend/domain/plugin/repository/tool_repository.go index 72f5bb5a..f6cab51d 100644 --- a/backend/domain/plugin/repository/tool_repository.go +++ b/backend/domain/plugin/repository/tool_repository.go @@ -19,7 +19,6 @@ package repository import ( "context" - "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin" "github.com/coze-dev/coze-studio/backend/domain/plugin/entity" ) @@ -54,8 +53,6 @@ type ToolRepository interface { MGetVersionAgentTool(ctx context.Context, agentID int64, vAgentTools []entity.VersionAgentTool) (tools []*entity.ToolInfo, err error) BatchCreateVersionAgentTools(ctx context.Context, agentID int64, agentVersion string, tools []*entity.ToolInfo) (err error) - UpdateDraftToolAndDebugExample(ctx context.Context, pluginID int64, doc *plugin.Openapi3T, updatedTool *entity.ToolInfo) (err error) - GetPluginAllDraftTools(ctx context.Context, pluginID int64, opts ...ToolSelectedOptions) (tools []*entity.ToolInfo, err error) GetPluginAllOnlineTools(ctx context.Context, pluginID int64) (tools []*entity.ToolInfo, err error) ListPluginDraftTools(ctx context.Context, pluginID int64, pageInfo entity.PageInfo) (tools []*entity.ToolInfo, total int64, err error) diff --git a/backend/domain/plugin/service/plugin_draft.go b/backend/domain/plugin/service/plugin_draft.go index 3b13d1b7..36a56e22 100644 --- a/backend/domain/plugin/service/plugin_draft.go +++ b/backend/domain/plugin/service/plugin_draft.go @@ -578,7 +578,7 @@ func (p *pluginServiceImpl) MGetDraftTools(ctx context.Context, toolIDs []int64) return tools, nil } -func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateToolDraftRequest) (err error) { +func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateDraftToolRequest) (err error) { draftPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, req.PluginID) if err != nil { return errorx.Wrapf(err, "GetDraftPlugin failed, pluginID=%d", req.PluginID) @@ -595,6 +595,14 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool return errorx.New(errno.ErrPluginRecordNotFound) } + if req.SaveExample != nil { + return p.updateDraftToolDebugExample(ctx, draftPlugin, draftTool, *req.SaveExample, req.DebugExample) + } + + return p.updateDraftTool(ctx, req, draftTool) +} + +func (p *pluginServiceImpl) updateDraftTool(ctx context.Context, req *UpdateDraftToolRequest, draftTool *entity.ToolInfo) (err error) { if req.Method != nil && req.SubURL != nil { api := entity.UniqueToolAPI{ SubURL: ptr.FromOrDefault(req.SubURL, ""), @@ -634,9 +642,6 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool if req.Desc != nil { op.Summary = *req.Desc } - if req.Parameters != nil { - op.Parameters = req.Parameters - } if req.APIExtend != nil { if op.Extensions == nil { op.Extensions = map[string]any{} @@ -647,6 +652,12 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool } } + // update request parameters + if req.Parameters != nil { + op.Parameters = req.Parameters + } + + // update request body if req.RequestBody == nil { op.RequestBody = draftTool.Operation.RequestBody } else { @@ -664,6 +675,7 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool op.RequestBody.Value.Content[model.MediaTypeJson] = mType } + // update responses if req.Responses == nil { op.Responses = draftTool.Operation.Responses } else { @@ -707,11 +719,24 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool Operation: op, } + err = p.toolRepo.UpdateDraftTool(ctx, updatedTool) + if err != nil { + return errorx.Wrapf(err, "UpdateDraftTool failed, toolID=%d", req.ToolID) + } + + return nil +} + +func (p *pluginServiceImpl) updateDraftToolDebugExample(ctx context.Context, draftPlugin *entity.PluginInfo, + draftTool *entity.ToolInfo, save bool, example *common.DebugExample) (err error) { + components := draftPlugin.OpenapiDoc.Components - if req.SaveExample != nil && !*req.SaveExample && - components != nil && components.Examples != nil { + + if !save && components != nil && components.Examples != nil { delete(components.Examples, draftTool.Operation.OperationID) - } else if req.DebugExample != nil { + } + + if save { if components == nil { components = &openapi3.Components{} } @@ -722,14 +747,14 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool draftPlugin.OpenapiDoc.Components = components reqExample, respExample := map[string]any{}, map[string]any{} - if req.DebugExample.ReqExample != "" { - err = sonic.UnmarshalString(req.DebugExample.ReqExample, &reqExample) + if example.ReqExample != "" { + err = sonic.UnmarshalString(example.ReqExample, &reqExample) if err != nil { return errorx.WrapByCode(err, errno.ErrPluginInvalidOpenapi3Doc, errorx.KV(errno.PluginMsgKey, "invalid request example")) } } - if req.DebugExample.RespExample != "" { - err = sonic.UnmarshalString(req.DebugExample.RespExample, &respExample) + if example.RespExample != "" { + err = sonic.UnmarshalString(example.RespExample, &respExample) if err != nil { return errorx.WrapByCode(err, errno.ErrPluginInvalidOpenapi3Doc, errorx.KV(errno.PluginMsgKey, "invalid response example")) } @@ -745,9 +770,9 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool } } - err = p.toolRepo.UpdateDraftToolAndDebugExample(ctx, draftPlugin.ID, draftPlugin.OpenapiDoc, updatedTool) + err = p.pluginRepo.UpdateDebugExample(ctx, draftPlugin.ID, draftPlugin.OpenapiDoc) if err != nil { - return errorx.Wrapf(err, "UpdateDraftToolAndDebugExample failed, pluginID=%d, toolID=%d", draftPlugin.ID, req.ToolID) + return errorx.Wrapf(err, "UpdateDebugExample failed, pluginID=%d", draftPlugin.ID) } return nil diff --git a/backend/domain/plugin/service/service.go b/backend/domain/plugin/service/service.go index d58c998b..22532c00 100644 --- a/backend/domain/plugin/service/service.go +++ b/backend/domain/plugin/service/service.go @@ -57,7 +57,7 @@ type PluginService interface { // Draft Tool MGetDraftTools(ctx context.Context, toolIDs []int64) (tools []*entity.ToolInfo, err error) - UpdateDraftTool(ctx context.Context, req *UpdateToolDraftRequest) (err error) + UpdateDraftTool(ctx context.Context, req *UpdateDraftToolRequest) (err error) ConvertToOpenapi3Doc(ctx context.Context, req *ConvertToOpenapi3DocRequest) (resp *ConvertToOpenapi3DocResponse) CreateDraftToolsWithCode(ctx context.Context, req *CreateDraftToolsWithCodeRequest) (resp *CreateDraftToolsWithCodeResponse, err error) CheckPluginToolsDebugStatus(ctx context.Context, pluginID int64) (err error) @@ -312,7 +312,7 @@ type PublishAPPPluginsResponse = model.PublishAPPPluginsResponse type MGetPluginLatestVersionResponse = model.MGetPluginLatestVersionResponse -type UpdateToolDraftRequest struct { +type UpdateDraftToolRequest struct { PluginID int64 ToolID int64 Name *string diff --git a/backend/internal/mock/domain/plugin/interface.go b/backend/internal/mock/domain/plugin/interface.go index 2c7afc66..c55b2921 100644 --- a/backend/internal/mock/domain/plugin/interface.go +++ b/backend/internal/mock/domain/plugin/interface.go @@ -651,7 +651,7 @@ func (mr *MockPluginServiceMockRecorder) UpdateDraftPluginWithCode(ctx, req any) } // UpdateDraftTool mocks base method. -func (m *MockPluginService) UpdateDraftTool(ctx context.Context, req *service.UpdateToolDraftRequest) error { +func (m *MockPluginService) UpdateDraftTool(ctx context.Context, req *service.UpdateDraftToolRequest) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateDraftTool", ctx, req) ret0, _ := ret[0].(error)