feat(plugin): product search

This commit is contained in:
lijunwen.gigoo
2025-10-10 14:43:59 +08:00
parent cd763e8600
commit 5871e41ef2
18 changed files with 124 additions and 129 deletions

View File

@ -40,7 +40,6 @@ import (
"github.com/coze-dev/coze-studio/backend/application/search"
"github.com/coze-dev/coze-studio/backend/application/singleagent"
"github.com/coze-dev/coze-studio/backend/application/template"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
)
@ -55,7 +54,6 @@ func PublicGetProductList(ctx context.Context, c *app.RequestContext) {
return
}
req.EntityType = ptr.Of(product_common.ProductEntityType_SaasPlugin)
var resp *product_public_api.GetProductListResponse
switch req.GetEntityType() {
case product_common.ProductEntityType_Plugin:

View File

@ -183,9 +183,9 @@ func parseChatflowParameters(ctx context.Context, ar *run.ChatV3Request) (map[st
if err := json.Unmarshal([]byte(*ar.Parameters), &parameters); err != nil {
return nil, errors.New("parameters field should be an object, not a string")
}
return parameters,nil
return parameters, nil
}
return parameters,nil
return parameters, nil
}
func (a *OpenapiAgentRunApplication) buildTools(ctx context.Context, shortcmd *run.ShortcutCommandDetail) ([]*entity.Tool, error) {

View File

@ -357,26 +357,11 @@ func (p *PluginApplicationService) getSaasPluginToolsList(ctx context.Context, p
return p.DomainSVC.BatchGetSaasPluginToolsInfo(ctx, pluginIDs)
}
func convertPluginsToSuggestions(plugins []*entity.PluginInfo) []*productAPI.ProductInfo {
suggestionProducts := make([]*productAPI.ProductInfo, 0, len(plugins))
suggestionSet := make(map[string]bool) // Use map to avoid duplicates
for _, plugin := range plugins {
if plugin.GetName() != "" && !suggestionSet[plugin.GetName()] {
suggestionProducts = append(suggestionProducts, convertPluginToProductInfo(plugin))
suggestionSet[plugin.GetName()] = true
}
}
return suggestionProducts
}
func (p *PluginApplicationService) GetCozeSaasPluginList(ctx context.Context, req *productAPI.GetProductListRequest) (resp *productAPI.GetProductListResponse, err error) {
domainResp, err := p.getSaasPluginList(ctx, &dto.ListSaasPluginProductsRequest{
PageNum: ptr.Of(req.PageNum),
PageSize: ptr.Of(req.PageSize),
Keyword: req.Keyword,
PageNum: ptr.Of(req.PageNum),
PageSize: ptr.Of(req.PageSize),
Keyword: req.Keyword,
EntityTypes: req.EntityTypes,
})
if err != nil {
@ -389,7 +374,7 @@ func (p *PluginApplicationService) GetCozeSaasPluginList(ctx context.Context, re
// tools
pluginIDs := make([]int64, 0, len(domainResp.Plugins))
for _,product := range domainResp.Plugins{
for _, product := range domainResp.Plugins {
pluginIDs = append(pluginIDs, product.ID)
}
@ -434,7 +419,7 @@ func (p *PluginApplicationService) PublicSearchProduct(ctx context.Context, req
}
// tools
pluginIDs := make([]int64, 0, len(domainResp.Plugins))
for _,product := range domainResp.Plugins{
for _, product := range domainResp.Plugins {
pluginIDs = append(pluginIDs, product.ID)
}
@ -466,7 +451,6 @@ func (p *PluginApplicationService) PublicSearchSuggest(ctx context.Context, req
PageSize: req.PageSize,
Keyword: req.Keyword,
EntityTypes: req.EntityTypes,
})
if err != nil {
logs.CtxErrorf(ctx, "ListSaasPluginProducts for suggestions failed: %v", err)
@ -476,7 +460,22 @@ func (p *PluginApplicationService) PublicSearchSuggest(ctx context.Context, req
}, nil
}
suggestionProducts := convertPluginsToSuggestions(domainResp.Plugins)
// tools
pluginIDs := make([]int64, 0, len(domainResp.Plugins))
for _, product := range domainResp.Plugins {
pluginIDs = append(pluginIDs, product.ID)
}
tools, err := p.getSaasPluginToolsList(ctx, pluginIDs)
if err != nil {
logs.CtxErrorf(ctx, "BatchGetSaasPluginToolsInfo failed: %v", err)
return &productAPI.SearchSuggestResponse{
Code: -1,
Message: "Failed to get SaaS plugin tools list",
}, nil
}
suggestionProducts := p.convertPluginsToProductInfos(ctx, domainResp.Plugins, tools)
return &productAPI.SearchSuggestResponse{
Code: 0,
@ -560,7 +559,6 @@ func (p *PluginApplicationService) GetProductCallInfo(ctx context.Context, req *
UserLevel: productAPI.UserLevel_Free,
}
data.CallCountLimit = &productAPI.ProductCallCountLimit{
IsUnlimited: benefit.IsUnlimited,
UsedCount: benefit.UsedCount,

View File

@ -39,7 +39,7 @@ func TestPluginApplicationService_GetCozeSaasPluginList(t *testing.T) {
defer ctrl.Finish()
mockDomainSVC := mockPlugin.NewMockPluginService(ctrl)
service := &PluginApplicationService{
DomainSVC: mockDomainSVC,
}
@ -53,7 +53,7 @@ func TestPluginApplicationService_GetCozeSaasPluginList(t *testing.T) {
createTestPluginInfo(1, "Test Plugin 1", "Description 1"),
createTestPluginInfo(2, "Test Plugin 2", "Description 2"),
}
domainResp := &dto.ListPluginProductsResponse{
Plugins: testPlugins,
Total: 2,
@ -146,7 +146,7 @@ func TestPluginApplicationService_GetCozeSaasPluginList(t *testing.T) {
createTestPluginInfo(400, "News Plugin", "Get latest news updates"),
createTestPluginInfo(500, "Email Plugin", "Send and manage emails"),
}
domainResp := &dto.ListPluginProductsResponse{
Plugins: testPlugins,
Total: 5,
@ -174,7 +174,7 @@ func TestPluginApplicationService_GetCozeSaasPluginList(t *testing.T) {
// Verify all plugins are converted correctly
expectedNames := []string{"Weather Plugin", "Translation Plugin", "Calculator Plugin", "News Plugin", "Email Plugin"}
expectedIDs := []int64{100, 200, 300, 400, 500}
for i, product := range resp.Data.Products {
assert.Equal(t, expectedIDs[i], product.MetaInfo.ID)
assert.Equal(t, expectedIDs[i], product.MetaInfo.EntityID)
@ -259,4 +259,4 @@ func createTestDomainResponse(plugins []*entity.PluginInfo) *dto.ListPluginProdu
Plugins: plugins,
Total: int64(len(plugins)),
}
}
}

View File

@ -44,8 +44,8 @@ type ToolInfo struct {
ActivatedStatus *consts.ActivatedStatus
DebugStatus *common.APIDebugStatus
Source *bot_common.PluginSource
Extra map[string]any
Source *bot_common.PluginSource
Extra map[string]any
Method *string
SubURL *string
@ -622,7 +622,7 @@ type ExecuteToolRequest struct {
ExecDraftTool bool // if true, execute draft tool
ExecScene consts.ExecuteScene
PluginSource *bot_common.PluginSource
PluginSource *bot_common.PluginSource
ArgumentsInJson string
}

View File

@ -30,8 +30,6 @@ type SearchSaasPluginRequest struct {
IsOfficial *bool `json:"is_official,omitempty"`
}
// SearchSaasPluginResponse represents the response from coze.cn search API
type SearchSaasPluginResponse struct {
Code int `json:"code"`
@ -136,7 +134,6 @@ type GetSaasPluginCallInfoResponse struct {
type GetSaasPluginCallInfoData struct {
}
type JsonSchemaType int32
const (
@ -162,10 +159,10 @@ type JsonSchema struct {
Defs map[string]*JsonSchema `json:"$defs,omitempty"`
Definitions map[string]*JsonSchema `json:"definitions,omitempty"` // deprecated but still allowed
Anchor string `json:"$anchor,omitempty"`
DynamicAnchor string `json:"$dynamicAnchor,omitempty"`
DynamicRef string `json:"$dynamicRef,omitempty"`
Vocabulary map[string]bool `json:"$vocabulary,omitempty"`
Anchor string `json:"$anchor,omitempty"`
DynamicAnchor string `json:"$dynamicAnchor,omitempty"`
DynamicRef string `json:"$dynamicRef,omitempty"`
Vocabulary map[string]bool `json:"$vocabulary,omitempty"`
// metadata
Title string `json:"title,omitempty"`
@ -177,17 +174,17 @@ type JsonSchema struct {
// validation
// Use Type for a single type, or Types for multiple types; never both.
Type JsonSchemaType `json:"type,omitempty"`
Types []JsonSchemaType `json:"types,omitempty"`
Enum []*AnyValue `json:"enum,omitempty"`
MultipleOf *float64 `json:"multipleOf,omitempty"`
Minimum *float64 `json:"minimum,omitempty"`
Maximum *float64 `json:"maximum,omitempty"`
ExclusiveMinimum *bool `json:"exclusiveMinimum,omitempty"`
ExclusiveMaximum *bool `json:"exclusiveMaximum,omitempty"`
MinLength *int32 `json:"minLength,omitempty"`
MaxLength *int32 `json:"maxLength,omitempty"`
Pattern string `json:"pattern,omitempty"`
Type JsonSchemaType `json:"type,omitempty"`
Types []JsonSchemaType `json:"types,omitempty"`
Enum []*AnyValue `json:"enum,omitempty"`
MultipleOf *float64 `json:"multipleOf,omitempty"`
Minimum *float64 `json:"minimum,omitempty"`
Maximum *float64 `json:"maximum,omitempty"`
ExclusiveMinimum *bool `json:"exclusiveMinimum,omitempty"`
ExclusiveMaximum *bool `json:"exclusiveMaximum,omitempty"`
MinLength *int32 `json:"minLength,omitempty"`
MaxLength *int32 `json:"maxLength,omitempty"`
Pattern string `json:"pattern,omitempty"`
// arrays
PrefixItems []*JsonSchema `json:"prefixItems,omitempty"`
@ -202,15 +199,15 @@ type JsonSchema struct {
UnevaluatedItems *JsonSchema `json:"unevaluatedItems,omitempty"`
// objects
MinProperties *int32 `json:"minProperties,omitempty"`
MaxProperties *int32 `json:"maxProperties,omitempty"`
Required []string `json:"required,omitempty"`
DependentRequired map[string][]string `json:"dependentRequired,omitempty"`
Properties map[string]*JsonSchema `json:"properties,omitempty"`
PatternProperties map[string]*JsonSchema `json:"patternProperties,omitempty"`
AdditionalProperties *JsonSchema `json:"additionalProperties,omitempty"`
PropertyNames *JsonSchema `json:"propertyNames,omitempty"`
UnevaluatedProperties *JsonSchema `json:"unevaluatedProperties,omitempty"`
MinProperties *int32 `json:"minProperties,omitempty"`
MaxProperties *int32 `json:"maxProperties,omitempty"`
Required []string `json:"required,omitempty"`
DependentRequired map[string][]string `json:"dependentRequired,omitempty"`
Properties map[string]*JsonSchema `json:"properties,omitempty"`
PatternProperties map[string]*JsonSchema `json:"patternProperties,omitempty"`
AdditionalProperties *JsonSchema `json:"additionalProperties,omitempty"`
PropertyNames *JsonSchema `json:"propertyNames,omitempty"`
UnevaluatedProperties *JsonSchema `json:"unevaluatedProperties,omitempty"`
// logic
AllOf []*JsonSchema `json:"allOf,omitempty"`
@ -265,13 +262,16 @@ func (js *JsonSchema) UnmarshalJSON(data []byte) error {
TypeString interface{} `json:"type"`
*Alias
}{
Alias: (*Alias)(js),
Alias: (*Alias)(&JsonSchema{}),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
// Copy all fields from aux.Alias to js
*js = JsonSchema(*aux.Alias)
// Handle the type field conversion
if aux.TypeString != nil {
switch v := aux.TypeString.(type) {

View File

@ -60,8 +60,8 @@ func (t toolPO) ToDO() *entity.ToolInfo {
Operation: t.Operation,
ActivatedStatus: ptr.Of(consts.ActivatedStatus(t.ActivatedStatus)),
Source: bot_common.PluginSourcePtr(bot_common.PluginSource(t.Source)),
Extra: t.Ext,
Source: bot_common.PluginSourcePtr(bot_common.PluginSource(t.Source)),
Extra: t.Ext,
}
}

View File

@ -56,8 +56,8 @@ func (t toolVersionPO) ToDO() *entity.ToolInfo {
Method: ptr.Of(t.Method),
Operation: t.Operation,
Source: bot_common.PluginSourcePtr(bot_common.PluginSource(t.Source)),
Extra: t.Ext,
Source: bot_common.PluginSourcePtr(bot_common.PluginSource(t.Source)),
Extra: t.Ext,
}
}

View File

@ -186,15 +186,15 @@ func (p *pluginServiceImpl) getDraftAgentPluginInfo(ctx context.Context, req *mo
}
var (
exist bool
exist bool
)
if req.PluginSource != nil && *req.PluginSource == bot_common.PluginSource_FromSaas{
if req.PluginSource != nil && *req.PluginSource == bot_common.PluginSource_FromSaas {
//TODOget plugin info from saas
} else {
onlineTool, exist, err = p.toolRepo.GetOnlineTool(ctx, req.ToolID)
if err != nil {
return nil, nil, errorx.Wrapf(err, "GetOnlineTool failed, toolID=%d", req.ToolID)
return nil, nil, errorx.Wrapf(err, "GetOnlineTool failed, toolID=%d", req.ToolID)
}
if !exist {
return nil, nil, errorx.New(errno.ErrPluginRecordNotFound)

View File

@ -99,10 +99,10 @@ func (p *pluginServiceImpl) ListPluginProducts(ctx context.Context, req *dto.Lis
// official plugins
officialPlugins, _, err := p.pluginRepo.ListCustomOnlinePlugins(ctx, 999999, dto.PageInfo{
Page: 1,
Size: 1000,
Page: 1,
Size: 1000,
OrderByACS: ptr.Of(true),
SortBy:ptr.Of(dto.SortByCreatedAt),
SortBy: ptr.Of(dto.SortByCreatedAt),
})
if err != nil {
return nil, errorx.Wrapf(err, "ListCustomOnlinePlugins failed, spaceID=999999")

View File

@ -49,12 +49,12 @@ type CozePlugin struct {
func (p *pluginServiceImpl) ListSaasPluginProducts(ctx context.Context, req *domainDto.ListSaasPluginProductsRequest) (resp *domainDto.ListPluginProductsResponse, err error) {
searchReq := &domainDto.SearchSaasPluginRequest{
PageNum: ptr.Of(int(*req.PageNum)),
PageSize: ptr.Of(int(*req.PageSize)),
Keyword: req.Keyword,
PageNum: ptr.Of(int(*req.PageNum)),
PageSize: ptr.Of(int(*req.PageSize)),
Keyword: req.Keyword,
IsOfficial: req.IsOfficial,
}
plugins, hasMore,err := p.fetchSaasPluginsFromCoze(ctx, searchReq)
plugins, hasMore, err := p.fetchSaasPluginsFromCoze(ctx, searchReq)
if err != nil {
return nil, errorx.Wrapf(err, "fetchSaasPluginsFromCoze failed")
}
@ -88,25 +88,25 @@ func (p *pluginServiceImpl) BatchGetSaasPluginToolsInfo(ctx context.Context, plu
}
var apiResp struct {
Plugins []struct {
Items []struct {
Tools []struct {
ToolID string `json:"tool_id"`
Description string `json:"description"`
InputSchema *domainDto.JsonSchema `json:"inputSchema"`
Name string `json:"name"`
OutputSchema *domainDto.JsonSchema `json:"outputSchema"`
ToolID string `json:"tool_id"`
Description string `json:"description"`
InputSchema *domainDto.JsonSchema `json:"inputSchema"`
Name string `json:"name"`
OutputSchema *domainDto.JsonSchema `json:"outputSchema"`
} `json:"tools"`
McpJSON string `json:"mcp_json"`
} `json:"plugins"`
} `json:"items"`
}
logs.CtxInfof(ctx, "call coze.cn /v1/plugins/mget API, resp: %v", string(resp.Data))
if err := json.Unmarshal(resp.Data, &apiResp); err != nil {
return nil, errorx.Wrapf(err, "failed to parse coze.cn API response")
}
result := make(map[int64][]*entity.ToolInfo)
for i, plugin := range apiResp.Plugins {
for i, plugin := range apiResp.Items {
if i >= len(pluginIDs) {
break
}
@ -186,11 +186,11 @@ func convertFromJsonSchema(schema *domainDto.JsonSchema) []*pluginCommon.APIPara
}
param := &pluginCommon.APIParameter{
Name: name,
Desc: propSchema.Description,
IsRequired: requiredFields[name],
Type: mapJsonSchemaTypeToParameterType(propSchema.Type),
Location: pluginCommon.ParameterLocation_Body,
Name: name,
Desc: propSchema.Description,
IsRequired: requiredFields[name],
Type: mapJsonSchemaTypeToParameterType(propSchema.Type),
Location: pluginCommon.ParameterLocation_Body,
}
// Handle nested object type
if propSchema.Type == domainDto.JsonSchemaType_OBJECT && len(propSchema.Properties) > 0 {
@ -212,7 +212,6 @@ func convertFromJsonSchema(schema *domainDto.JsonSchema) []*pluginCommon.APIPara
return parameters
}
func (p *pluginServiceImpl) fetchSaasPluginsFromCoze(ctx context.Context, searchReq *domainDto.SearchSaasPluginRequest) ([]*entity.PluginInfo, bool, error) {
searchResp, err := p.searchSaasPlugin(ctx, searchReq)
@ -271,6 +270,7 @@ func convertSaasPluginItemToEntity(item *domainDto.SaasPluginItem) *entity.Plugi
CreatedAt: metaInfo.ListedAt,
UpdatedAt: metaInfo.ListedAt,
Manifest: manifest,
Source: ptr.Of(bot_common.PluginSource_FromSaas),
}
return entity.NewPluginInfo(pluginInfo)

View File

@ -53,15 +53,15 @@ func TestConvertSaasPluginItemToEntity_WithNewFields(t *testing.T) {
IsOfficial: true,
},
PluginInfo: &domainDto.SaasPluginInfo{
FavoriteCount: 1,
Heat: 0,
AvgExecDurationMs: 114.61111,
CallCount: 20,
Description: "Test plugin description",
TotalToolsCount: 2,
BotsUseCount: 7,
AssociatedBotsUseCount: 0,
SuccessRate: 0.8333349999999999,
FavoriteCount: 1,
Heat: 0,
AvgExecDurationMs: 114.61111,
CallCount: 20,
Description: "Test plugin description",
TotalToolsCount: 2,
BotsUseCount: 7,
AssociatedBotsUseCount: 0,
SuccessRate: 0.8333349999999999,
},
}
@ -73,7 +73,7 @@ func TestConvertSaasPluginItemToEntity_WithNewFields(t *testing.T) {
assert.Equal(t, "Test Plugin", plugin.GetName())
assert.Equal(t, "Test plugin description", plugin.GetDesc())
assert.Equal(t, "https://example.com/icon.png", plugin.GetIconURI())
// This test verifies that:
// 1. ProductURL field is accessible (even if not directly used in conversion)
// 2. UserID string type works correctly

View File

@ -83,21 +83,21 @@ func TestSearchSaasPluginResponse_JSONUnmarshal(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 0, searchResp.Code)
assert.Equal(t, "", searchResp.Msg)
// Verify detail field
assert.NotNil(t, searchResp.Detail)
assert.Equal(t, "2025092821165570E59640C37BF984D370", searchResp.Detail.LogID)
// Verify data field
assert.NotNil(t, searchResp.Data)
assert.True(t, searchResp.Data.HasMore)
assert.Len(t, searchResp.Data.Items, 1)
// Verify plugin item
item := searchResp.Data.Items[0]
assert.NotNil(t, item.MetaInfo)
assert.NotNil(t, item.PluginInfo)
// Verify metainfo fields
metaInfo := item.MetaInfo
assert.Equal(t, "7546432661141602358", metaInfo.ProductID)
@ -105,15 +105,15 @@ func TestSearchSaasPluginResponse_JSONUnmarshal(t *testing.T) {
assert.Equal(t, "ppe_test_官方付费", metaInfo.Name)
assert.Equal(t, "https://www.coze.cn/store/plugin/7546432661141602358", metaInfo.ProductURL)
assert.True(t, metaInfo.IsOfficial)
// Verify user_info field (should be string now)
assert.NotNil(t, metaInfo.UserInfo)
assert.Equal(t, "3235179593473241", metaInfo.UserInfo.UserID)
assert.Equal(t, "testlbsZEOkZJP", metaInfo.UserInfo.NickName)
// Verify plugin_info fields
pluginInfo := item.PluginInfo
assert.Equal(t, 1, pluginInfo.FavoriteCount)
assert.Equal(t, int64(20), pluginInfo.CallCount)
assert.Equal(t, 2, pluginInfo.TotalToolsCount)
}
}

View File

@ -285,7 +285,7 @@ func (h *httpCallImpl) buildRequestBody(ctx context.Context, op *model.Openapi3O
return body, contentType, nil
}
func(h *httpCallImpl) injectCozeSaasAPIToken (ctx context.Context, httpReq *http.Request) (errMsg string, err error){
func (h *httpCallImpl) injectCozeSaasAPIToken(ctx context.Context, httpReq *http.Request) (errMsg string, err error) {
// apiToken := os.Getenv(consts.CozeSaasAPIKey)
apiToken := "pat_OjlRXGYdXDLHDv10dZuav02A7SomHZkXTjx0fbZ9xUDIrssE7tZ07gI2TzABBQ7M"

View File

@ -70,7 +70,7 @@ type GetEnterpriseBenefitResponse struct {
// BenefitData represents the benefit data
type BenefitData struct {
BasicInfo *BasicInfo `json:"basic_info,omitempty"`
BasicInfo *BasicInfo `json:"basic_info,omitempty"`
BenefitInfo []*BenefitInfo `json:"benefit_info,omitempty"`
}
@ -81,27 +81,27 @@ type BasicInfo struct {
// BenefitInfo represents the benefit information
type BenefitInfo struct {
ResourceID string `json:"resource_id,omitempty"`
BenefitType BenefitType `json:"benefit_type,omitempty"`
Basic *BenefitTypeInfoItem `json:"basic,omitempty"` // Basic value
ResourceID string `json:"resource_id,omitempty"`
BenefitType BenefitType `json:"benefit_type,omitempty"`
Basic *BenefitTypeInfoItem `json:"basic,omitempty"` // Basic value
Extra []*BenefitTypeInfoItem `json:"extra,omitempty"` // Extra values, may not exist
}
// BenefitTypeInfoItem represents a benefit type info item
type BenefitTypeInfoItem struct {
ItemID string `json:"item_id,omitempty"`
ItemInfo *CommonCounter `json:"item_info,omitempty"`
Status EntityBenefitStatus `json:"status,omitempty"`
BenefitID string `json:"benefit_id,omitempty"`
ItemID string `json:"item_id,omitempty"`
ItemInfo *CommonCounter `json:"item_info,omitempty"`
Status EntityBenefitStatus `json:"status,omitempty"`
BenefitID string `json:"benefit_id,omitempty"`
}
// CommonCounter represents a common counter
type CommonCounter struct {
Used float64 `json:"used,omitempty"` // Used amount when Strategy == ByQuota, returns 0 if no usage data
Total float64 `json:"total,omitempty"` // Total limit when Strategy == ByQuota
Strategy ResourceUsageStrategy `json:"strategy,omitempty"` // Resource usage strategy
StartAt int64 `json:"start_at,omitempty"` // Start time in seconds
EndAt int64 `json:"end_at,omitempty"` // End time in seconds
Used float64 `json:"used,omitempty"` // Used amount when Strategy == ByQuota, returns 0 if no usage data
Total float64 `json:"total,omitempty"` // Total limit when Strategy == ByQuota
Strategy ResourceUsageStrategy `json:"strategy,omitempty"` // Resource usage strategy
StartAt int64 `json:"start_at,omitempty"` // Start time in seconds
EndAt int64 `json:"end_at,omitempty"` // End time in seconds
}
// String methods for enums (for better debugging and logging)

View File

@ -93,7 +93,6 @@ func (s *CozeUserService) GetEnterpriseBenefit(ctx context.Context, req *entity.
return nil, errorx.New(errno.ErrUserResourceNotFound, errorx.KV("reason", "API call failed"))
}
var benefitData entity.BenefitData
if err := json.Unmarshal(resp.Data, &benefitData); err != nil {
logs.CtxErrorf(ctx, "failed to parse benefit data: %v", err)

View File

@ -254,7 +254,7 @@ type FCParam struct {
PluginVersion string `json:"plugin_version"`
IsDraft bool `json:"is_draft"`
PluginSource bot_common.PluginSource `json:"plugin_source"`
PluginSource *bot_common.PluginSource `json:"plugin_source"`
FCSetting *struct {
RequestParameters []*workflow.APIParameter `json:"request_params"`
ResponseParameters []*workflow.APIParameter `json:"response_params"`
@ -306,8 +306,8 @@ type VariableAggregator struct {
}
type PluginAPIParam struct {
APIParams []*Param `json:"apiParam"`
PluginSource bot_common.PluginSource `json:"pluginSource"`
APIParams []*Param `json:"apiParam"`
PluginSource *bot_common.PluginSource `json:"pluginSource"`
}
type CodeRunner struct {

View File

@ -82,7 +82,7 @@ var path2Table2Columns2Model = map[string]map[string]map[string]any{
"plugin": {
"manifest": &plugin.PluginManifest{},
"openapi_doc": &plugin.Openapi3T{},
"ext": map[string]any{},
"ext": map[string]any{},
},
"plugin_draft": {
"manifest": &plugin.PluginManifest{},
@ -91,7 +91,7 @@ var path2Table2Columns2Model = map[string]map[string]map[string]any{
"plugin_version": {
"manifest": &plugin.PluginManifest{},
"openapi_doc": &plugin.Openapi3T{},
"ext": map[string]any{},
"ext": map[string]any{},
},
"agent_tool_draft": {
"operation": &plugin.Openapi3Operation{},