feat(plugin): product search
This commit is contained in:
@ -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:
|
||||
|
||||
@ -183,9 +183,9 @@ func parseChatflowParameters(ctx context.Context, ar *run.ChatV3Request) (map[st
|
||||
if err := json.Unmarshal([]byte(*ar.Parameters), ¶meters); 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) {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
//TODO::get 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)
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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{},
|
||||
|
||||
Reference in New Issue
Block a user