feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
204
backend/application/singleagent/create.go
Normal file
204
backend/application/singleagent/create.go
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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 singleagent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
modelmgrEntity "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/modelmgr"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/singleagent"
|
||||
intelligence "github.com/coze-dev/coze-studio/backend/api/model/intelligence/common"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/bot_common"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/developer_api"
|
||||
"github.com/coze-dev/coze-studio/backend/application/base/ctxutil"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/agent/singleagent/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/modelmgr"
|
||||
searchEntity "github.com/coze-dev/coze-studio/backend/domain/search/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
func (s *SingleAgentApplicationService) CreateSingleAgentDraft(ctx context.Context, req *developer_api.DraftBotCreateRequest) (*developer_api.DraftBotCreateResponse, error) {
|
||||
do, err := s.draftBotCreateRequestToSingleAgent(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userID := ctxutil.MustGetUIDFromCtx(ctx)
|
||||
agentID, err := s.DomainSVC.CreateSingleAgentDraft(ctx, userID, do)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.appContext.EventBus.PublishProject(ctx, &searchEntity.ProjectDomainEvent{
|
||||
OpType: searchEntity.Created,
|
||||
Project: &searchEntity.ProjectDocument{
|
||||
Status: intelligence.IntelligenceStatus_Using,
|
||||
Type: intelligence.IntelligenceType_Bot,
|
||||
ID: agentID,
|
||||
SpaceID: &req.SpaceID,
|
||||
OwnerID: &userID,
|
||||
Name: &do.Name,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &developer_api.DraftBotCreateResponse{Data: &developer_api.DraftBotCreateData{
|
||||
BotID: agentID,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) draftBotCreateRequestToSingleAgent(ctx context.Context, req *developer_api.DraftBotCreateRequest) (*entity.SingleAgent, error) {
|
||||
sa, err := s.newDefaultSingleAgent(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sa.SpaceID = req.SpaceID
|
||||
sa.Name = req.GetName()
|
||||
sa.Desc = req.GetDescription()
|
||||
sa.IconURI = req.GetIconURI()
|
||||
|
||||
return sa, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) newDefaultSingleAgent(ctx context.Context) (*entity.SingleAgent, error) {
|
||||
mi, err := s.defaultModelInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
return &entity.SingleAgent{
|
||||
SingleAgent: &singleagent.SingleAgent{
|
||||
OnboardingInfo: &bot_common.OnboardingInfo{},
|
||||
ModelInfo: mi,
|
||||
Prompt: &bot_common.PromptInfo{},
|
||||
Plugin: []*bot_common.PluginInfo{},
|
||||
Knowledge: &bot_common.Knowledge{
|
||||
TopK: ptr.Of(int64(1)),
|
||||
MinScore: ptr.Of(float64(0.01)),
|
||||
SearchStrategy: ptr.Of(bot_common.SearchStrategy_SemanticSearch),
|
||||
RecallStrategy: &bot_common.RecallStrategy{
|
||||
UseNl2sql: ptr.Of(true),
|
||||
UseRerank: ptr.Of(true),
|
||||
UseRewrite: ptr.Of(true),
|
||||
},
|
||||
},
|
||||
Workflow: []*bot_common.WorkflowInfo{},
|
||||
SuggestReply: &bot_common.SuggestReplyInfo{},
|
||||
JumpConfig: &bot_common.JumpConfig{},
|
||||
Database: []*bot_common.Database{},
|
||||
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) defaultModelInfo(ctx context.Context) (*bot_common.ModelInfo, error) {
|
||||
modelResp, err := s.appContext.ModelMgrDomainSVC.ListModel(ctx, &modelmgr.ListModelRequest{
|
||||
Status: []modelmgrEntity.ModelEntityStatus{modelmgrEntity.ModelEntityStatusDefault, modelmgrEntity.ModelEntityStatusInUse},
|
||||
Limit: 1,
|
||||
Cursor: nil,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(modelResp.ModelList) == 0 {
|
||||
return nil, errorx.New(errno.ErrAgentResourceNotFound, errorx.KV("type", "model"), errorx.KV("id", "default"))
|
||||
}
|
||||
|
||||
dm := modelResp.ModelList[0]
|
||||
|
||||
var temperature *float64
|
||||
if tp, ok := dm.FindParameter(modelmgrEntity.Temperature); ok {
|
||||
t, err := tp.GetFloat(modelmgrEntity.DefaultTypeBalance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
temperature = ptr.Of(t)
|
||||
}
|
||||
|
||||
var maxTokens *int32
|
||||
if tp, ok := dm.FindParameter(modelmgrEntity.MaxTokens); ok {
|
||||
t, err := tp.GetInt(modelmgrEntity.DefaultTypeBalance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
maxTokens = ptr.Of(int32(t))
|
||||
} else if dm.Meta.ConnConfig.MaxTokens != nil {
|
||||
maxTokens = ptr.Of(int32(*dm.Meta.ConnConfig.MaxTokens))
|
||||
}
|
||||
|
||||
var topP *float64
|
||||
if tp, ok := dm.FindParameter(modelmgrEntity.TopP); ok {
|
||||
t, err := tp.GetFloat(modelmgrEntity.DefaultTypeBalance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
topP = ptr.Of(t)
|
||||
}
|
||||
|
||||
var topK *int32
|
||||
if tp, ok := dm.FindParameter(modelmgrEntity.TopK); ok {
|
||||
t, err := tp.GetInt(modelmgrEntity.DefaultTypeBalance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
topK = ptr.Of(int32(t))
|
||||
}
|
||||
|
||||
var frequencyPenalty *float64
|
||||
if tp, ok := dm.FindParameter(modelmgrEntity.FrequencyPenalty); ok {
|
||||
t, err := tp.GetFloat(modelmgrEntity.DefaultTypeBalance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frequencyPenalty = ptr.Of(t)
|
||||
}
|
||||
|
||||
var presencePenalty *float64
|
||||
if tp, ok := dm.FindParameter(modelmgrEntity.PresencePenalty); ok {
|
||||
t, err := tp.GetFloat(modelmgrEntity.DefaultTypeBalance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
presencePenalty = ptr.Of(t)
|
||||
}
|
||||
|
||||
return &bot_common.ModelInfo{
|
||||
ModelId: ptr.Of(dm.ID),
|
||||
Temperature: temperature,
|
||||
MaxTokens: maxTokens,
|
||||
TopP: topP,
|
||||
FrequencyPenalty: frequencyPenalty,
|
||||
PresencePenalty: presencePenalty,
|
||||
TopK: topK,
|
||||
ModelStyle: bot_common.ModelStylePtr(bot_common.ModelStyle_Balance),
|
||||
ShortMemoryPolicy: &bot_common.ShortMemoryPolicy{
|
||||
ContextMode: bot_common.ContextModePtr(bot_common.ContextMode_FunctionCall_2),
|
||||
HistoryRound: ptr.Of[int32](3),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
177
backend/application/singleagent/duplicate.go
Normal file
177
backend/application/singleagent/duplicate.go
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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 singleagent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
intelligence "github.com/coze-dev/coze-studio/backend/api/model/intelligence/common"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/developer_api"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/project_memory"
|
||||
"github.com/coze-dev/coze-studio/backend/application/base/ctxutil"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossplugin"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/agent/singleagent/entity"
|
||||
searchEntity "github.com/coze-dev/coze-studio/backend/domain/search/entity"
|
||||
shortcutCMDEntity "github.com/coze-dev/coze-studio/backend/domain/shortcutcmd/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/conv"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
)
|
||||
|
||||
type duplicateAgentResourceFn func(ctx context.Context, appContext *ServiceComponents, oldAgent, newAgent *entity.SingleAgent) (*entity.SingleAgent, error)
|
||||
|
||||
func (s *SingleAgentApplicationService) DuplicateDraftBot(ctx context.Context, req *developer_api.DuplicateDraftBotRequest) (*developer_api.DuplicateDraftBotResponse, error) {
|
||||
draftAgent, err := s.ValidateAgentDraftAccess(ctx, req.BotID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newAgentID, err := s.appContext.IDGen.GenID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userID := ctxutil.MustGetUIDFromCtx(ctx)
|
||||
duplicateInfo := &entity.DuplicateInfo{
|
||||
NewAgentID: newAgentID,
|
||||
SpaceID: req.GetSpaceID(),
|
||||
UserID: userID,
|
||||
DraftAgent: draftAgent,
|
||||
}
|
||||
|
||||
newAgent, err := s.DomainSVC.DuplicateInMemory(ctx, duplicateInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
duplicateFns := []duplicateAgentResourceFn{
|
||||
duplicateVariables,
|
||||
duplicatePlugin,
|
||||
duplicateShortCommand,
|
||||
}
|
||||
|
||||
for _, fn := range duplicateFns {
|
||||
newAgent, err = fn(ctx, s.appContext, draftAgent, newAgent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = s.DomainSVC.CreateSingleAgentDraftWithID(ctx, userID, newAgentID, newAgent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userInfo, err := s.appContext.UserDomainSVC.GetUserInfo(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.appContext.EventBus.PublishProject(ctx, &searchEntity.ProjectDomainEvent{
|
||||
OpType: searchEntity.Created,
|
||||
Project: &searchEntity.ProjectDocument{
|
||||
Status: intelligence.IntelligenceStatus_Using,
|
||||
Type: intelligence.IntelligenceType_Bot,
|
||||
ID: newAgent.AgentID,
|
||||
SpaceID: &req.SpaceID,
|
||||
OwnerID: &userID,
|
||||
Name: &newAgent.Name,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &developer_api.DuplicateDraftBotResponse{
|
||||
Data: &developer_api.DuplicateDraftBotData{
|
||||
BotID: newAgent.AgentID,
|
||||
Name: newAgent.Name,
|
||||
UserInfo: &developer_api.Creator{
|
||||
ID: userID,
|
||||
Name: userInfo.Name,
|
||||
AvatarURL: userInfo.IconURL,
|
||||
Self: userID == draftAgent.CreatorID,
|
||||
UserUniqueName: userInfo.UniqueName,
|
||||
UserLabel: nil,
|
||||
},
|
||||
},
|
||||
Code: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func duplicateVariables(ctx context.Context, appContext *ServiceComponents, oldAgent, newAgent *entity.SingleAgent) (*entity.SingleAgent, error) {
|
||||
if oldAgent.VariablesMetaID == nil || *oldAgent.VariablesMetaID <= 0 {
|
||||
return newAgent, nil
|
||||
}
|
||||
|
||||
vars, err := appContext.VariablesDomainSVC.GetVariableMetaByID(ctx, *oldAgent.VariablesMetaID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vars.ID = 0
|
||||
vars.BizID = conv.Int64ToStr(newAgent.AgentID)
|
||||
vars.BizType = project_memory.VariableConnector_Bot
|
||||
vars.Version = ""
|
||||
vars.CreatorID = newAgent.CreatorID
|
||||
|
||||
varMetaID, err := appContext.VariablesDomainSVC.UpsertMeta(ctx, vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newAgent.VariablesMetaID = &varMetaID
|
||||
|
||||
return newAgent, nil
|
||||
}
|
||||
|
||||
func duplicatePlugin(ctx context.Context, _ *ServiceComponents, oldAgent, newAgent *entity.SingleAgent) (*entity.SingleAgent, error) {
|
||||
err := crossplugin.DefaultSVC().DuplicateDraftAgentTools(ctx, oldAgent.AgentID, newAgent.AgentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newAgent, nil
|
||||
}
|
||||
|
||||
func duplicateShortCommand(ctx context.Context, appContext *ServiceComponents, oldAgent, newAgent *entity.SingleAgent) (*entity.SingleAgent, error) {
|
||||
metas, err := appContext.ShortcutCMDDomainSVC.ListCMD(ctx, &shortcutCMDEntity.ListMeta{
|
||||
SpaceID: oldAgent.SpaceID,
|
||||
ObjectID: oldAgent.AgentID,
|
||||
IsOnline: 0,
|
||||
CommandIDs: slices.Transform(oldAgent.ShortcutCommand, func(a string) int64 {
|
||||
return conv.StrToInt64D(a, 0)
|
||||
}),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shortcutCommandIDs := make([]string, 0, len(metas))
|
||||
for _, meta := range metas {
|
||||
meta.ObjectID = newAgent.AgentID
|
||||
meta.CreatorID = newAgent.CreatorID
|
||||
do, err := appContext.ShortcutCMDDomainSVC.CreateCMD(ctx, meta)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shortcutCommandIDs = append(shortcutCommandIDs, conv.Int64ToStr(do.CommandID))
|
||||
}
|
||||
|
||||
newAgent.ShortcutCommand = shortcutCommandIDs
|
||||
|
||||
return newAgent, nil
|
||||
}
|
||||
587
backend/application/singleagent/get.go
Normal file
587
backend/application/singleagent/get.go
Normal file
@@ -0,0 +1,587 @@
|
||||
/*
|
||||
* 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 singleagent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
|
||||
knowledgeModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/knowledge"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/bot_common"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/playground"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/agent/singleagent/entity"
|
||||
knowledge "github.com/coze-dev/coze-studio/backend/domain/knowledge/service"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/modelmgr"
|
||||
modelEntity "github.com/coze-dev/coze-studio/backend/domain/modelmgr/entity"
|
||||
pluginEntity "github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/service"
|
||||
shortcutCMDEntity "github.com/coze-dev/coze-studio/backend/domain/shortcutcmd/entity"
|
||||
workflowEntity "github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/conv"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
func (s *SingleAgentApplicationService) GetAgentBotInfo(ctx context.Context, req *playground.GetDraftBotInfoAgwRequest) (*playground.GetDraftBotInfoAgwResponse, error) {
|
||||
agentInfo, err := s.DomainSVC.GetSingleAgent(ctx, req.GetBotID(), req.GetVersion())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if agentInfo == nil {
|
||||
return nil, errorx.New(errno.ErrAgentInvalidParamCode, errorx.KVf("msg", "agent %d not found", req.GetBotID()))
|
||||
}
|
||||
|
||||
vo, err := s.singleAgentDraftDo2Vo(ctx, agentInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
klInfos, err := s.fetchKnowledgeDetails(ctx, agentInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modelInfos, err := s.fetchModelDetails(ctx, agentInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
toolInfos, err := s.fetchToolDetails(ctx, agentInfo, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pluginInfos, err := s.fetchPluginDetails(ctx, agentInfo, toolInfos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workflowInfos, err := s.fetchWorkflowDetails(ctx, agentInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shortCutCmdResp, err := s.fetchShortcutCMD(ctx, agentInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workflowDetailMap, err := workflowDo2Vo(workflowInfos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &playground.GetDraftBotInfoAgwResponse{
|
||||
Data: &playground.GetDraftBotInfoAgwData{
|
||||
BotInfo: vo,
|
||||
BotOptionData: &playground.BotOptionData{
|
||||
ModelDetailMap: modelInfoDo2Vo(modelInfos),
|
||||
KnowledgeDetailMap: knowledgeInfoDo2Vo(klInfos),
|
||||
PluginAPIDetailMap: toolInfoDo2Vo(toolInfos),
|
||||
PluginDetailMap: s.pluginInfoDo2Vo(ctx, pluginInfos),
|
||||
WorkflowDetailMap: workflowDetailMap,
|
||||
ShortcutCommandList: shortCutCmdResp,
|
||||
},
|
||||
SpaceID: agentInfo.SpaceID,
|
||||
Editable: ptr.Of(true),
|
||||
Deletable: ptr.Of(true),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) fetchShortcutCMD(ctx context.Context, agentInfo *entity.SingleAgent) ([]*playground.ShortcutCommand, error) {
|
||||
var cmdVOs []*playground.ShortcutCommand
|
||||
if len(agentInfo.ShortcutCommand) == 0 {
|
||||
return cmdVOs, nil
|
||||
}
|
||||
|
||||
cmdDOs, err := s.appContext.ShortcutCMDDomainSVC.ListCMD(ctx, &shortcutCMDEntity.ListMeta{
|
||||
SpaceID: agentInfo.SpaceID,
|
||||
ObjectID: agentInfo.AgentID,
|
||||
CommandIDs: slices.Transform(agentInfo.ShortcutCommand, func(a string) int64 {
|
||||
return conv.StrToInt64D(a, 0)
|
||||
}),
|
||||
})
|
||||
|
||||
logs.CtxInfof(ctx, "fetchShortcutCMD cmdDOs = %v, err = %v", conv.DebugJsonToStr(cmdDOs), err)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmdVOs = s.shortcutCMDDo2Vo(cmdDOs)
|
||||
return cmdVOs, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) shortcutCMDDo2Vo(cmdDOs []*shortcutCMDEntity.ShortcutCmd) []*playground.ShortcutCommand {
|
||||
return slices.Transform(cmdDOs, func(cmdDO *shortcutCMDEntity.ShortcutCmd) *playground.ShortcutCommand {
|
||||
return &playground.ShortcutCommand{
|
||||
ObjectID: cmdDO.ObjectID,
|
||||
CommandID: cmdDO.CommandID,
|
||||
CommandName: cmdDO.CommandName,
|
||||
ShortcutCommand: cmdDO.ShortcutCommand,
|
||||
Description: cmdDO.Description,
|
||||
SendType: playground.SendType(cmdDO.SendType),
|
||||
ToolType: playground.ToolType(cmdDO.ToolType),
|
||||
WorkFlowID: conv.Int64ToStr(cmdDO.WorkFlowID),
|
||||
PluginID: conv.Int64ToStr(cmdDO.PluginID),
|
||||
PluginAPIName: cmdDO.PluginToolName,
|
||||
PluginAPIID: cmdDO.PluginToolID,
|
||||
ShortcutIcon: cmdDO.ShortcutIcon,
|
||||
TemplateQuery: cmdDO.TemplateQuery,
|
||||
ComponentsList: cmdDO.Components,
|
||||
CardSchema: cmdDO.CardSchema,
|
||||
ToolInfo: cmdDO.ToolInfo,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) fetchModelDetails(ctx context.Context, agentInfo *entity.SingleAgent) ([]*modelEntity.Model, error) {
|
||||
if agentInfo.ModelInfo.ModelId == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
modelID := agentInfo.ModelInfo.GetModelId()
|
||||
modelInfos, err := s.appContext.ModelMgrDomainSVC.MGetModelByID(ctx, &modelmgr.MGetModelRequest{
|
||||
IDs: []int64{modelID},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetch model(%d) details failed: %v", modelID, err)
|
||||
}
|
||||
|
||||
return modelInfos, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) fetchKnowledgeDetails(ctx context.Context, agentInfo *entity.SingleAgent) ([]*knowledgeModel.Knowledge, error) {
|
||||
knowledgeIDs := make([]int64, 0, len(agentInfo.Knowledge.KnowledgeInfo))
|
||||
for _, v := range agentInfo.Knowledge.KnowledgeInfo {
|
||||
id, err := conv.StrToInt64(v.GetId())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid knowledge id: %s", v.GetId())
|
||||
}
|
||||
knowledgeIDs = append(knowledgeIDs, id)
|
||||
}
|
||||
|
||||
if len(knowledgeIDs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
listResp, err := s.appContext.KnowledgeDomainSVC.ListKnowledge(ctx, &knowledge.ListKnowledgeRequest{
|
||||
IDs: knowledgeIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetch knowledge details failed: %v", err)
|
||||
}
|
||||
|
||||
return listResp.KnowledgeList, err
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) fetchToolDetails(ctx context.Context, agentInfo *entity.SingleAgent, req *playground.GetDraftBotInfoAgwRequest) ([]*pluginEntity.ToolInfo, error) {
|
||||
return s.appContext.PluginDomainSVC.MGetAgentTools(ctx, &service.MGetAgentToolsRequest{
|
||||
SpaceID: agentInfo.SpaceID,
|
||||
AgentID: req.GetBotID(),
|
||||
IsDraft: true,
|
||||
VersionAgentTools: slices.Transform(agentInfo.Plugin, func(a *bot_common.PluginInfo) pluginEntity.VersionAgentTool {
|
||||
return pluginEntity.VersionAgentTool{
|
||||
ToolID: a.GetApiId(),
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) fetchPluginDetails(ctx context.Context, agentInfo *entity.SingleAgent, toolInfos []*pluginEntity.ToolInfo) ([]*pluginEntity.PluginInfo, error) {
|
||||
vPlugins := make([]pluginEntity.VersionPlugin, 0, len(agentInfo.Plugin))
|
||||
vPluginMap := make(map[string]bool, len(agentInfo.Plugin))
|
||||
for _, v := range toolInfos {
|
||||
k := fmt.Sprintf("%d:%s", v.PluginID, v.GetVersion())
|
||||
if vPluginMap[k] {
|
||||
continue
|
||||
}
|
||||
vPluginMap[k] = true
|
||||
vPlugins = append(vPlugins, pluginEntity.VersionPlugin{
|
||||
PluginID: v.PluginID,
|
||||
Version: v.GetVersion(),
|
||||
})
|
||||
}
|
||||
return s.appContext.PluginDomainSVC.MGetVersionPlugins(ctx, vPlugins)
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) fetchWorkflowDetails(ctx context.Context, agentInfo *entity.SingleAgent) ([]*workflowEntity.Workflow, error) {
|
||||
if len(agentInfo.Workflow) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
policy := &vo.MGetPolicy{
|
||||
MetaQuery: vo.MetaQuery{
|
||||
IDs: slices.Transform(agentInfo.Workflow, func(a *bot_common.WorkflowInfo) int64 {
|
||||
return a.GetWorkflowId()
|
||||
}),
|
||||
},
|
||||
QType: vo.FromLatestVersion,
|
||||
}
|
||||
ret, _, err := s.appContext.WorkflowDomainSVC.MGet(ctx, policy)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetch workflow details failed: %v", err)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func modelInfoDo2Vo(modelInfos []*modelEntity.Model) map[int64]*playground.ModelDetail {
|
||||
return slices.ToMap(modelInfos, func(e *modelEntity.Model) (int64, *playground.ModelDetail) {
|
||||
return e.ID, toModelDetail(e)
|
||||
})
|
||||
}
|
||||
|
||||
func toModelDetail(m *modelEntity.Model) *playground.ModelDetail {
|
||||
mm := m.Meta
|
||||
|
||||
return &playground.ModelDetail{
|
||||
Name: ptr.Of(m.Name),
|
||||
ModelName: ptr.Of(m.Meta.Name),
|
||||
ModelID: ptr.Of(m.ID),
|
||||
ModelFamily: ptr.Of(int64(mm.Protocol.TOModelClass())),
|
||||
ModelIconURL: ptr.Of(mm.IconURL),
|
||||
}
|
||||
}
|
||||
|
||||
func knowledgeInfoDo2Vo(klInfos []*knowledgeModel.Knowledge) map[string]*playground.KnowledgeDetail {
|
||||
return slices.ToMap(klInfos, func(e *knowledgeModel.Knowledge) (string, *playground.KnowledgeDetail) {
|
||||
return fmt.Sprintf("%v", e.ID), &playground.KnowledgeDetail{
|
||||
ID: ptr.Of(fmt.Sprintf("%d", e.ID)),
|
||||
Name: ptr.Of(e.Name),
|
||||
IconURL: ptr.Of(e.IconURL),
|
||||
FormatType: func() playground.DataSetType {
|
||||
switch e.Type {
|
||||
case knowledgeModel.DocumentTypeText:
|
||||
return playground.DataSetType_Text
|
||||
case knowledgeModel.DocumentTypeTable:
|
||||
return playground.DataSetType_Table
|
||||
case knowledgeModel.DocumentTypeImage:
|
||||
return playground.DataSetType_Image
|
||||
}
|
||||
return playground.DataSetType_Text
|
||||
}(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func toolInfoDo2Vo(toolInfos []*pluginEntity.ToolInfo) map[int64]*playground.PluginAPIDetal {
|
||||
return slices.ToMap(toolInfos, func(e *pluginEntity.ToolInfo) (int64, *playground.PluginAPIDetal) {
|
||||
return e.ID, &playground.PluginAPIDetal{
|
||||
ID: ptr.Of(e.ID),
|
||||
Name: ptr.Of(e.GetName()),
|
||||
Description: ptr.Of(e.GetDesc()),
|
||||
PluginID: ptr.Of(e.PluginID),
|
||||
Parameters: parametersDo2Vo(e.Operation),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) pluginInfoDo2Vo(ctx context.Context, pluginInfos []*pluginEntity.PluginInfo) map[int64]*playground.PluginDetal {
|
||||
return slices.ToMap(pluginInfos, func(v *pluginEntity.PluginInfo) (int64, *playground.PluginDetal) {
|
||||
e := v.PluginInfo
|
||||
|
||||
var iconURL string
|
||||
if e.GetIconURI() != "" {
|
||||
var err error
|
||||
iconURL, err = s.appContext.TosClient.GetObjectUrl(ctx, e.GetIconURI())
|
||||
if err != nil {
|
||||
logs.CtxErrorf(ctx, "get icon url failed, err = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return e.ID, &playground.PluginDetal{
|
||||
ID: ptr.Of(e.ID),
|
||||
Name: ptr.Of(e.GetName()),
|
||||
Description: ptr.Of(e.GetDesc()),
|
||||
PluginType: (*int64)(&e.PluginType),
|
||||
IconURL: &iconURL,
|
||||
PluginStatus: (*int64)(ptr.Of(plugin_develop_common.PluginStatus_PUBLISHED)),
|
||||
IsOfficial: func() *bool {
|
||||
if e.SpaceID == 0 {
|
||||
return ptr.Of(true)
|
||||
}
|
||||
return ptr.Of(false)
|
||||
}(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func parametersDo2Vo(op *plugin.Openapi3Operation) []*playground.PluginParameter {
|
||||
var convertReqBody func(paramName string, isRequired bool, sc *openapi3.Schema) *playground.PluginParameter
|
||||
convertReqBody = func(paramName string, isRequired bool, sc *openapi3.Schema) *playground.PluginParameter {
|
||||
if disabledParam(sc) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var assistType *int64
|
||||
if v, ok := sc.Extensions[plugin.APISchemaExtendAssistType]; ok {
|
||||
if _v, ok := v.(string); ok {
|
||||
assistType = toParameterAssistType(_v)
|
||||
}
|
||||
}
|
||||
|
||||
paramInfo := &playground.PluginParameter{
|
||||
Name: ptr.Of(paramName),
|
||||
Type: ptr.Of(sc.Type),
|
||||
Description: ptr.Of(sc.Description),
|
||||
IsRequired: ptr.Of(isRequired),
|
||||
AssistType: assistType,
|
||||
}
|
||||
|
||||
switch sc.Type {
|
||||
case openapi3.TypeObject:
|
||||
required := slices.ToMap(sc.Required, func(e string) (string, bool) {
|
||||
return e, true
|
||||
})
|
||||
|
||||
subParams := make([]*playground.PluginParameter, 0, len(sc.Properties))
|
||||
for subParamName, prop := range sc.Properties {
|
||||
subParamInfo := convertReqBody(subParamName, required[subParamName], prop.Value)
|
||||
if subParamInfo != nil {
|
||||
subParams = append(subParams, subParamInfo)
|
||||
}
|
||||
}
|
||||
|
||||
paramInfo.SubParameters = subParams
|
||||
|
||||
return paramInfo
|
||||
case openapi3.TypeArray:
|
||||
paramInfo.SubType = ptr.Of(sc.Items.Value.Type)
|
||||
if sc.Items.Value.Type != openapi3.TypeObject {
|
||||
return paramInfo
|
||||
}
|
||||
|
||||
required := slices.ToMap(sc.Required, func(e string) (string, bool) {
|
||||
return e, true
|
||||
})
|
||||
|
||||
subParams := make([]*playground.PluginParameter, 0, len(sc.Items.Value.Properties))
|
||||
for subParamName, prop := range sc.Items.Value.Properties {
|
||||
subParamInfo := convertReqBody(subParamName, required[subParamName], prop.Value)
|
||||
if subParamInfo != nil {
|
||||
subParams = append(subParams, subParamInfo)
|
||||
}
|
||||
}
|
||||
|
||||
paramInfo.SubParameters = subParams
|
||||
|
||||
return paramInfo
|
||||
default:
|
||||
return paramInfo
|
||||
}
|
||||
}
|
||||
|
||||
var params []*playground.PluginParameter
|
||||
|
||||
for _, prop := range op.Parameters {
|
||||
paramVal := prop.Value
|
||||
schemaVal := paramVal.Schema.Value
|
||||
if schemaVal.Type == openapi3.TypeObject || schemaVal.Type == openapi3.TypeArray {
|
||||
continue
|
||||
}
|
||||
|
||||
if disabledParam(prop.Value.Schema.Value) {
|
||||
continue
|
||||
}
|
||||
|
||||
var assistType *int64
|
||||
if v, ok := schemaVal.Extensions[plugin.APISchemaExtendAssistType]; ok {
|
||||
if _v, ok := v.(string); ok {
|
||||
assistType = toParameterAssistType(_v)
|
||||
}
|
||||
}
|
||||
|
||||
params = append(params, &playground.PluginParameter{
|
||||
Name: ptr.Of(paramVal.Name),
|
||||
Description: ptr.Of(paramVal.Description),
|
||||
IsRequired: ptr.Of(paramVal.Required),
|
||||
Type: ptr.Of(schemaVal.Type),
|
||||
AssistType: assistType,
|
||||
})
|
||||
}
|
||||
|
||||
if op.RequestBody == nil || op.RequestBody.Value == nil || len(op.RequestBody.Value.Content) == 0 {
|
||||
return params
|
||||
}
|
||||
|
||||
for _, mType := range op.RequestBody.Value.Content {
|
||||
schemaVal := mType.Schema.Value
|
||||
if len(schemaVal.Properties) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
required := slices.ToMap(schemaVal.Required, func(e string) (string, bool) {
|
||||
return e, true
|
||||
})
|
||||
|
||||
for paramName, prop := range schemaVal.Properties {
|
||||
paramInfo := convertReqBody(paramName, required[paramName], prop.Value)
|
||||
if paramInfo != nil {
|
||||
params = append(params, paramInfo)
|
||||
}
|
||||
}
|
||||
|
||||
break // 只取一种 MIME
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
func toParameterAssistType(assistType string) *int64 {
|
||||
if assistType == "" {
|
||||
return nil
|
||||
}
|
||||
switch plugin.APIFileAssistType(assistType) {
|
||||
case plugin.AssistTypeFile:
|
||||
return ptr.Of(int64(plugin_develop_common.AssistParameterType_CODE))
|
||||
case plugin.AssistTypeImage:
|
||||
return ptr.Of(int64(plugin_develop_common.AssistParameterType_IMAGE))
|
||||
case plugin.AssistTypeDoc:
|
||||
return ptr.Of(int64(plugin_develop_common.AssistParameterType_DOC))
|
||||
case plugin.AssistTypePPT:
|
||||
return ptr.Of(int64(plugin_develop_common.AssistParameterType_PPT))
|
||||
case plugin.AssistTypeCode:
|
||||
return ptr.Of(int64(plugin_develop_common.AssistParameterType_CODE))
|
||||
case plugin.AssistTypeExcel:
|
||||
return ptr.Of(int64(plugin_develop_common.AssistParameterType_EXCEL))
|
||||
case plugin.AssistTypeZIP:
|
||||
return ptr.Of(int64(plugin_develop_common.AssistParameterType_ZIP))
|
||||
case plugin.AssistTypeVideo:
|
||||
return ptr.Of(int64(plugin_develop_common.AssistParameterType_VIDEO))
|
||||
case plugin.AssistTypeAudio:
|
||||
return ptr.Of(int64(plugin_develop_common.AssistParameterType_AUDIO))
|
||||
case plugin.AssistTypeTXT:
|
||||
return ptr.Of(int64(plugin_develop_common.AssistParameterType_TXT))
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func workflowDo2Vo(wfInfos []*workflowEntity.Workflow) (map[int64]*playground.WorkflowDetail, error) {
|
||||
result := make(map[int64]*playground.WorkflowDetail, len(wfInfos))
|
||||
for _, e := range wfInfos {
|
||||
parameters, err := slices.TransformWithErrorCheck(e.InputParams, toPluginParameter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[e.ID] = &playground.WorkflowDetail{
|
||||
ID: ptr.Of(e.ID),
|
||||
Name: ptr.Of(e.Name),
|
||||
Description: ptr.Of(e.Desc),
|
||||
IconURL: ptr.Of(e.IconURL),
|
||||
PluginID: ptr.Of(e.ID),
|
||||
APIDetail: &playground.PluginAPIDetal{
|
||||
ID: ptr.Of(e.ID),
|
||||
Name: ptr.Of(e.Name),
|
||||
Description: ptr.Of(e.Desc),
|
||||
PluginID: ptr.Of(e.ID),
|
||||
Parameters: parameters,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func toPluginParameter(info *vo.NamedTypeInfo) (*playground.PluginParameter, error) {
|
||||
if info == nil {
|
||||
return nil, fmt.Errorf("named type info is nil")
|
||||
}
|
||||
p := &playground.PluginParameter{
|
||||
Name: ptr.Of(info.Name),
|
||||
Description: ptr.Of(info.Desc),
|
||||
IsRequired: ptr.Of(info.Required),
|
||||
}
|
||||
|
||||
switch info.Type {
|
||||
case vo.DataTypeString, vo.DataTypeFile, vo.DataTypeTime:
|
||||
p.Type = ptr.Of("string")
|
||||
if info.Type == vo.DataTypeFile {
|
||||
p.AssistType = toWorkflowParameterAssistType(string(*info.FileType))
|
||||
}
|
||||
|
||||
case vo.DataTypeInteger:
|
||||
p.Type = ptr.Of("integer")
|
||||
case vo.DataTypeNumber:
|
||||
p.Type = ptr.Of("number")
|
||||
case vo.DataTypeBoolean:
|
||||
p.Type = ptr.Of("boolean")
|
||||
case vo.DataTypeObject:
|
||||
p.Type = ptr.Of("object")
|
||||
p.SubParameters = make([]*playground.PluginParameter, 0, len(info.Properties))
|
||||
for _, sub := range info.Properties {
|
||||
subParameter, err := toPluginParameter(sub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.SubParameters = append(p.SubParameters, subParameter)
|
||||
}
|
||||
case vo.DataTypeArray:
|
||||
p.Type = ptr.Of("array")
|
||||
eleParameter, err := toPluginParameter(info.ElemTypeInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.SubType = eleParameter.Type
|
||||
p.SubParameters = []*playground.PluginParameter{eleParameter}
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown named type info type: %s", info.Type)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func toWorkflowParameterAssistType(assistType string) *int64 {
|
||||
if assistType == "" {
|
||||
return nil
|
||||
}
|
||||
switch vo.FileSubType(assistType) {
|
||||
case vo.FileTypeDefault:
|
||||
return ptr.Of(int64(workflow.AssistParameterType_DEFAULT))
|
||||
case vo.FileTypeImage:
|
||||
return ptr.Of(int64(workflow.AssistParameterType_IMAGE))
|
||||
case vo.FileTypeDocument:
|
||||
return ptr.Of(int64(workflow.AssistParameterType_DOC))
|
||||
case vo.FileTypePPT:
|
||||
return ptr.Of(int64(workflow.AssistParameterType_PPT))
|
||||
case vo.FileTypeCode:
|
||||
return ptr.Of(int64(workflow.AssistParameterType_CODE))
|
||||
case vo.FileTypeExcel:
|
||||
return ptr.Of(int64(workflow.AssistParameterType_EXCEL))
|
||||
case vo.FileTypeZip:
|
||||
return ptr.Of(int64(workflow.AssistParameterType_ZIP))
|
||||
case vo.FileTypeVideo:
|
||||
return ptr.Of(int64(workflow.AssistParameterType_VIDEO))
|
||||
case vo.FileTypeAudio:
|
||||
return ptr.Of(int64(workflow.AssistParameterType_AUDIO))
|
||||
case vo.FileTypeTxt:
|
||||
return ptr.Of(int64(workflow.AssistParameterType_TXT))
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
94
backend/application/singleagent/image.go
Normal file
94
backend/application/singleagent/image.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 singleagent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/bot_common"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/developer_api"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/playground"
|
||||
)
|
||||
|
||||
func (s *SingleAgentApplicationService) GetUploadAuthToken(ctx context.Context, req *developer_api.GetUploadAuthTokenRequest) (*developer_api.GetUploadAuthTokenResponse, error) {
|
||||
|
||||
authToken, err := s.getAuthToken(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prefix := s.getUploadPrefix(req.Scene, req.DataType)
|
||||
|
||||
return &developer_api.GetUploadAuthTokenResponse{
|
||||
Data: &developer_api.GetUploadAuthTokenData{
|
||||
ServiceID: authToken.ServiceID,
|
||||
UploadPathPrefix: prefix,
|
||||
UploadHost: authToken.UploadHost,
|
||||
Auth: &developer_api.UploadAuthTokenInfo{
|
||||
AccessKeyID: authToken.AccessKeyID,
|
||||
SecretAccessKey: authToken.SecretAccessKey,
|
||||
SessionToken: authToken.SessionToken,
|
||||
ExpiredTime: authToken.ExpiredTime,
|
||||
CurrentTime: authToken.CurrentTime,
|
||||
},
|
||||
Schema: authToken.HostScheme,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
func (s *SingleAgentApplicationService) getAuthToken(ctx context.Context) (*bot_common.AuthToken, error) {
|
||||
uploadAuthToken, err := s.appContext.ImageX.GetUploadAuth(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authToken := &bot_common.AuthToken{
|
||||
ServiceID: s.appContext.ImageX.GetServerID(),
|
||||
AccessKeyID: uploadAuthToken.AccessKeyID,
|
||||
SecretAccessKey: uploadAuthToken.SecretAccessKey,
|
||||
SessionToken: uploadAuthToken.SessionToken,
|
||||
ExpiredTime: uploadAuthToken.ExpiredTime,
|
||||
CurrentTime: uploadAuthToken.CurrentTime,
|
||||
UploadHost: s.appContext.ImageX.GetUploadHost(ctx),
|
||||
HostScheme: uploadAuthToken.HostScheme,
|
||||
}
|
||||
return authToken, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) getUploadPrefix(scene, dataType string) string {
|
||||
return strings.Replace(scene, "_", "-", -1) + "-" + dataType
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) GetImagexShortUrl(ctx context.Context, req *playground.GetImagexShortUrlRequest) (*playground.GetImagexShortUrlResponse, error) {
|
||||
urlInfo := make(map[string]*playground.UrlInfo, len(req.Uris))
|
||||
for _, uri := range req.Uris {
|
||||
resURL, err := s.appContext.ImageX.GetResourceURL(ctx, uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
urlInfo[uri] = &playground.UrlInfo{
|
||||
URL: resURL.URL,
|
||||
ReviewStatus: true,
|
||||
}
|
||||
}
|
||||
|
||||
return &playground.GetImagexShortUrlResponse{
|
||||
Data: &playground.GetImagexShortUrlData{
|
||||
URLInfo: urlInfo,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
85
backend/application/singleagent/init.go
Normal file
85
backend/application/singleagent/init.go
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package singleagent
|
||||
|
||||
import (
|
||||
"github.com/cloudwego/eino/compose"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/agent/singleagent/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/agent/singleagent/repository"
|
||||
singleagent "github.com/coze-dev/coze-studio/backend/domain/agent/singleagent/service"
|
||||
connector "github.com/coze-dev/coze-studio/backend/domain/connector/service"
|
||||
knowledge "github.com/coze-dev/coze-studio/backend/domain/knowledge/service"
|
||||
database "github.com/coze-dev/coze-studio/backend/domain/memory/database/service"
|
||||
variables "github.com/coze-dev/coze-studio/backend/domain/memory/variables/service"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/modelmgr"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/service"
|
||||
search "github.com/coze-dev/coze-studio/backend/domain/search/service"
|
||||
shortcutCmd "github.com/coze-dev/coze-studio/backend/domain/shortcutcmd/service"
|
||||
user "github.com/coze-dev/coze-studio/backend/domain/user/service"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/imagex"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/impl/chatmodel"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/jsoncache"
|
||||
)
|
||||
|
||||
type (
|
||||
SingleAgent = singleagent.SingleAgent
|
||||
)
|
||||
|
||||
var SingleAgentSVC *SingleAgentApplicationService
|
||||
|
||||
type ServiceComponents struct {
|
||||
IDGen idgen.IDGenerator
|
||||
DB *gorm.DB
|
||||
Cache *redis.Client
|
||||
TosClient storage.Storage
|
||||
ImageX imagex.ImageX
|
||||
EventBus search.ProjectEventBus
|
||||
CounterRepo repository.CounterRepository
|
||||
|
||||
KnowledgeDomainSVC knowledge.Knowledge
|
||||
ModelMgrDomainSVC modelmgr.Manager
|
||||
PluginDomainSVC service.PluginService
|
||||
WorkflowDomainSVC workflow.Service
|
||||
UserDomainSVC user.User
|
||||
VariablesDomainSVC variables.Variables
|
||||
ConnectorDomainSVC connector.Connector
|
||||
DatabaseDomainSVC database.Database
|
||||
ShortcutCMDDomainSVC shortcutCmd.ShortcutCmd
|
||||
CPStore compose.CheckPointStore
|
||||
}
|
||||
|
||||
func InitService(c *ServiceComponents) (*SingleAgentApplicationService, error) {
|
||||
domainComponents := &singleagent.Components{
|
||||
AgentDraftRepo: repository.NewSingleAgentRepo(c.DB, c.IDGen, c.Cache),
|
||||
AgentVersionRepo: repository.NewSingleAgentVersionRepo(c.DB, c.IDGen),
|
||||
PublishInfoRepo: jsoncache.New[entity.PublishInfo]("agent:publish:last:", c.Cache),
|
||||
CounterRepo: repository.NewCounterRepo(c.Cache),
|
||||
CPStore: c.CPStore,
|
||||
ModelFactory: chatmodel.NewDefaultFactory(),
|
||||
}
|
||||
|
||||
singleAgentDomainSVC := singleagent.NewService(domainComponents)
|
||||
SingleAgentSVC = newApplicationService(c, singleAgentDomainSVC)
|
||||
|
||||
return SingleAgentSVC, nil
|
||||
}
|
||||
260
backend/application/singleagent/publish.go
Normal file
260
backend/application/singleagent/publish.go
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* 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 singleagent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/database"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/intelligence/common"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/developer_api"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/playground"
|
||||
"github.com/coze-dev/coze-studio/backend/application/base/ctxutil"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/agent/singleagent/entity"
|
||||
search "github.com/coze-dev/coze-studio/backend/domain/search/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/conv"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/taskgroup"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
func (s *SingleAgentApplicationService) PublishAgent(ctx context.Context, req *developer_api.PublishDraftBotRequest) (*developer_api.PublishDraftBotResponse, error) {
|
||||
draftAgent, err := s.ValidateAgentDraftAccess(ctx, req.BotID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
version, err := s.getPublishAgentVersion(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
connectorIDs := make([]int64, 0, len(req.Connectors))
|
||||
for v := range req.Connectors {
|
||||
var id int64
|
||||
id, err = strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !entity.PublishConnectorIDWhiteList[id] {
|
||||
return nil, errorx.New(errno.ErrAgentPermissionCode, errorx.KV("msg", fmt.Sprintf("connector %d not allowed", id)))
|
||||
}
|
||||
|
||||
connectorIDs = append(connectorIDs, id)
|
||||
}
|
||||
|
||||
p := &entity.SingleAgentPublish{
|
||||
ConnectorIds: connectorIDs,
|
||||
Version: version,
|
||||
PublishID: req.GetPublishID(),
|
||||
PublishInfo: req.HistoryInfo,
|
||||
}
|
||||
|
||||
publishFns := []publishFn{
|
||||
publishAgentVariables,
|
||||
publishAgentPlugins,
|
||||
publishShortcutCommand,
|
||||
publishDatabase,
|
||||
}
|
||||
|
||||
for _, pubFn := range publishFns {
|
||||
draftAgent, err = pubFn(ctx, s.appContext, p, draftAgent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = s.DomainSVC.SavePublishRecord(ctx, p, draftAgent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tasks := taskgroup.NewUninterruptibleTaskGroup(ctx, len(connectorIDs))
|
||||
publishResult := make(map[string]*developer_api.ConnectorBindResult, len(connectorIDs))
|
||||
lock := sync.Mutex{}
|
||||
|
||||
for _, connectorID := range connectorIDs {
|
||||
tasks.Go(func() error {
|
||||
_, err = s.DomainSVC.CreateSingleAgent(ctx, connectorID, version, draftAgent)
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "create single agent failed: %v, agentID: %d, connectorID: %d , version : %s", err, draftAgent.AgentID, connectorID, version)
|
||||
lock.Lock()
|
||||
publishResult[conv.Int64ToStr(connectorID)] = &developer_api.ConnectorBindResult{
|
||||
PublishResultStatus: ptr.Of(developer_api.PublishResultStatus_Failed),
|
||||
}
|
||||
lock.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// do other connector publish logic if need
|
||||
|
||||
lock.Lock()
|
||||
publishResult[conv.Int64ToStr(connectorID)] = &developer_api.ConnectorBindResult{
|
||||
PublishResultStatus: ptr.Of(developer_api.PublishResultStatus_Success),
|
||||
}
|
||||
lock.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
_ = tasks.Wait()
|
||||
|
||||
err = s.appContext.EventBus.PublishProject(ctx, &search.ProjectDomainEvent{
|
||||
OpType: search.Updated,
|
||||
Project: &search.ProjectDocument{
|
||||
ID: draftAgent.AgentID,
|
||||
HasPublished: ptr.Of(1),
|
||||
PublishTimeMS: ptr.Of(time.Now().UnixMilli()),
|
||||
Type: common.IntelligenceType_Bot,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "publish project event failed, agentID: %d, err : %v", draftAgent.AgentID, err)
|
||||
}
|
||||
|
||||
return &developer_api.PublishDraftBotResponse{
|
||||
Data: &developer_api.PublishDraftBotData{
|
||||
CheckNotPass: false,
|
||||
PublishResult: publishResult,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) getPublishAgentVersion(ctx context.Context, req *developer_api.PublishDraftBotRequest) (string, error) {
|
||||
version := req.GetCommitVersion()
|
||||
if version != "" {
|
||||
return version, nil
|
||||
}
|
||||
|
||||
v, err := s.appContext.IDGen.GenID(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
version = fmt.Sprintf("%v", v)
|
||||
|
||||
return version, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) GetAgentPopupInfo(ctx context.Context, req *playground.GetBotPopupInfoRequest) (*playground.GetBotPopupInfoResponse, error) {
|
||||
uid := ctxutil.MustGetUIDFromCtx(ctx)
|
||||
agentPopupCountInfo := make(map[playground.BotPopupType]int64, len(req.BotPopupTypes))
|
||||
|
||||
for _, agentPopupType := range req.BotPopupTypes {
|
||||
count, err := s.DomainSVC.GetAgentPopupCount(ctx, uid, req.GetBotID(), agentPopupType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
agentPopupCountInfo[agentPopupType] = count
|
||||
}
|
||||
|
||||
return &playground.GetBotPopupInfoResponse{
|
||||
Data: &playground.BotPopupInfoData{
|
||||
BotPopupCountInfo: agentPopupCountInfo,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) UpdateAgentPopupInfo(ctx context.Context, req *playground.UpdateBotPopupInfoRequest) (*playground.UpdateBotPopupInfoResponse, error) {
|
||||
uid := ctxutil.MustGetUIDFromCtx(ctx)
|
||||
|
||||
err := s.DomainSVC.IncrAgentPopupCount(ctx, uid, req.GetBotID(), req.GetBotPopupType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &playground.UpdateBotPopupInfoResponse{
|
||||
Code: 0,
|
||||
Msg: "success",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) GetPublishConnectorList(ctx context.Context, req *developer_api.PublishConnectorListRequest) (*developer_api.PublishConnectorListResponse, error) {
|
||||
data, err := s.DomainSVC.GetPublishConnectorList(ctx, req.BotID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &developer_api.PublishConnectorListResponse{
|
||||
PublishConnectorList: data.PublishConnectorList,
|
||||
Code: 0,
|
||||
Msg: "success",
|
||||
}, nil
|
||||
}
|
||||
|
||||
type publishFn func(ctx context.Context, appContext *ServiceComponents, publishInfo *entity.SingleAgentPublish, agent *entity.SingleAgent) (*entity.SingleAgent, error)
|
||||
|
||||
func publishAgentVariables(ctx context.Context, appContext *ServiceComponents, publishInfo *entity.SingleAgentPublish, agent *entity.SingleAgent) (*entity.SingleAgent, error) {
|
||||
draftAgent := agent
|
||||
if draftAgent.VariablesMetaID != nil || *draftAgent.VariablesMetaID == 0 {
|
||||
return draftAgent, nil
|
||||
}
|
||||
|
||||
var newVariableMetaID int64
|
||||
newVariableMetaID, err := appContext.VariablesDomainSVC.PublishMeta(ctx, *draftAgent.VariablesMetaID, publishInfo.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
draftAgent.VariablesMetaID = ptr.Of(newVariableMetaID)
|
||||
|
||||
return draftAgent, nil
|
||||
}
|
||||
|
||||
func publishAgentPlugins(ctx context.Context, appContext *ServiceComponents, publishInfo *entity.SingleAgentPublish, agent *entity.SingleAgent) (*entity.SingleAgent, error) {
|
||||
err := appContext.PluginDomainSVC.PublishAgentTools(ctx, agent.AgentID, publishInfo.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return agent, nil
|
||||
}
|
||||
|
||||
func publishShortcutCommand(ctx context.Context, appContext *ServiceComponents, publishInfo *entity.SingleAgentPublish, agent *entity.SingleAgent) (*entity.SingleAgent, error) {
|
||||
logs.CtxInfof(ctx, "publishShortcutCommand agentID: %d, shortcutCommand: %v", agent.AgentID, agent.ShortcutCommand)
|
||||
if agent.ShortcutCommand == nil || len(agent.ShortcutCommand) == 0 {
|
||||
return agent, nil
|
||||
}
|
||||
cmdIDs := slices.Transform(agent.ShortcutCommand, func(a string) int64 {
|
||||
return conv.StrToInt64D(a, 0)
|
||||
})
|
||||
err := appContext.ShortcutCMDDomainSVC.PublishCMDs(ctx, agent.AgentID, cmdIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return agent, nil
|
||||
}
|
||||
|
||||
func publishDatabase(ctx context.Context, appContext *ServiceComponents, publishInfo *entity.SingleAgentPublish, agent *entity.SingleAgent) (*entity.SingleAgent, error) {
|
||||
onlineResp, err := appContext.DatabaseDomainSVC.PublishDatabase(ctx, &database.PublishDatabaseRequest{AgentID: agent.AgentID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
agent.Database = onlineResp.OnlineDatabases
|
||||
return agent, nil
|
||||
}
|
||||
733
backend/application/singleagent/single_agent.go
Normal file
733
backend/application/singleagent/single_agent.go
Normal file
@@ -0,0 +1,733 @@
|
||||
/*
|
||||
* 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 singleagent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
shortcutCmd "github.com/coze-dev/coze-studio/backend/domain/shortcutcmd/service"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/types/consts"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/database"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
intelligence "github.com/coze-dev/coze-studio/backend/api/model/intelligence/common"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/bot_common"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/developer_api"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/playground"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/table"
|
||||
"github.com/coze-dev/coze-studio/backend/application/base/ctxutil"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossdatabase"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/agent/singleagent/entity"
|
||||
singleagent "github.com/coze-dev/coze-studio/backend/domain/agent/singleagent/service"
|
||||
variableEntity "github.com/coze-dev/coze-studio/backend/domain/memory/variables/entity"
|
||||
shortcutEntity "github.com/coze-dev/coze-studio/backend/domain/shortcutcmd/entity"
|
||||
|
||||
searchEntity "github.com/coze-dev/coze-studio/backend/domain/search/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/conv"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type SingleAgentApplicationService struct {
|
||||
appContext *ServiceComponents
|
||||
DomainSVC singleagent.SingleAgent
|
||||
ShortcutCMDSVC shortcutCmd.ShortcutCmd
|
||||
}
|
||||
|
||||
func newApplicationService(s *ServiceComponents, domain singleagent.SingleAgent) *SingleAgentApplicationService {
|
||||
return &SingleAgentApplicationService{
|
||||
appContext: s,
|
||||
DomainSVC: domain,
|
||||
ShortcutCMDSVC: s.ShortcutCMDDomainSVC,
|
||||
}
|
||||
}
|
||||
|
||||
const onboardingInfoMaxLength = 65535
|
||||
|
||||
func (s *SingleAgentApplicationService) generateOnboardingStr(onboardingInfo *bot_common.OnboardingInfo) (string, error) {
|
||||
onboarding := playground.OnboardingContent{}
|
||||
if onboardingInfo != nil {
|
||||
onboarding.Prologue = ptr.Of(onboardingInfo.GetPrologue())
|
||||
onboarding.SuggestedQuestions = onboardingInfo.GetSuggestedQuestions()
|
||||
onboarding.SuggestedQuestionsShowMode = onboardingInfo.SuggestedQuestionsShowMode
|
||||
}
|
||||
|
||||
onboardingInfoStr, err := sonic.MarshalString(onboarding)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return onboardingInfoStr, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) UpdateSingleAgentDraft(ctx context.Context, req *playground.UpdateDraftBotInfoAgwRequest) (*playground.UpdateDraftBotInfoAgwResponse, error) {
|
||||
if req.BotInfo.OnboardingInfo != nil {
|
||||
infoStr, err := s.generateOnboardingStr(req.BotInfo.OnboardingInfo)
|
||||
if err != nil {
|
||||
return nil, errorx.New(errno.ErrAgentPermissionCode, errorx.KV("msg", "onboarding_info invalidate"))
|
||||
}
|
||||
|
||||
if len(infoStr) > onboardingInfoMaxLength {
|
||||
return nil, errorx.New(errno.ErrAgentPermissionCode, errorx.KV("msg", "onboarding_info is too long"))
|
||||
}
|
||||
}
|
||||
|
||||
agentID := req.BotInfo.GetBotId()
|
||||
currentAgentInfo, err := s.ValidateAgentDraftAccess(ctx, agentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userID := ctxutil.MustGetUIDFromCtx(ctx)
|
||||
|
||||
updateAgentInfo, err := s.applyAgentUpdates(currentAgentInfo, req.BotInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.BotInfo.VariableList != nil {
|
||||
var (
|
||||
varsMetaID int64
|
||||
vars = variableEntity.NewVariablesWithAgentVariables(req.BotInfo.VariableList)
|
||||
)
|
||||
|
||||
varsMetaID, err = s.appContext.VariablesDomainSVC.UpsertBotMeta(ctx, agentID, "", userID, vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updateAgentInfo.VariablesMetaID = &varsMetaID
|
||||
}
|
||||
|
||||
err = s.DomainSVC.UpdateSingleAgentDraft(ctx, updateAgentInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.appContext.EventBus.PublishProject(ctx, &searchEntity.ProjectDomainEvent{
|
||||
OpType: searchEntity.Updated,
|
||||
Project: &searchEntity.ProjectDocument{
|
||||
ID: agentID,
|
||||
Name: &updateAgentInfo.Name,
|
||||
Type: intelligence.IntelligenceType_Bot,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &playground.UpdateDraftBotInfoAgwResponse{
|
||||
Data: &playground.UpdateDraftBotInfoAgwData{
|
||||
HasChange: ptr.Of(true),
|
||||
CheckNotPass: false,
|
||||
Branch: playground.BranchPtr(playground.Branch_PersonalDraft),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) UpdatePromptDisable(ctx context.Context, req *table.UpdateDatabaseBotSwitchRequest) (*table.UpdateDatabaseBotSwitchResponse, error) {
|
||||
agentID := req.GetBotID()
|
||||
draft, err := s.ValidateAgentDraftAccess(ctx, agentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(draft.Database) == 0 {
|
||||
return nil, fmt.Errorf("agent %d has no database", agentID) // TODO(@fanlv): 错误码
|
||||
}
|
||||
|
||||
dbInfos := draft.Database
|
||||
var found bool
|
||||
for _, db := range dbInfos {
|
||||
if db.GetTableId() == conv.Int64ToStr(req.GetDatabaseID()) {
|
||||
db.PromptDisabled = ptr.Of(req.GetPromptDisable())
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil, fmt.Errorf("database %d not found in agent %d", req.GetDatabaseID(), agentID) // TODO(@fanlv): 错误码
|
||||
}
|
||||
|
||||
draft.Database = dbInfos
|
||||
err = s.DomainSVC.UpdateSingleAgentDraft(ctx, draft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &table.UpdateDatabaseBotSwitchResponse{
|
||||
Code: 0,
|
||||
Msg: "success",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) UnBindDatabase(ctx context.Context, req *table.BindDatabaseToBotRequest) (*table.BindDatabaseToBotResponse, error) {
|
||||
agentID := req.GetBotID()
|
||||
draft, err := s.ValidateAgentDraftAccess(ctx, agentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(draft.Database) == 0 {
|
||||
return nil, fmt.Errorf("agent %d has no database", agentID)
|
||||
}
|
||||
|
||||
dbInfos := draft.Database
|
||||
var found bool
|
||||
newDBInfos := make([]*bot_common.Database, 0)
|
||||
for _, db := range dbInfos {
|
||||
if db.GetTableId() == conv.Int64ToStr(req.GetDatabaseID()) {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
newDBInfos = append(newDBInfos, db)
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil, fmt.Errorf("database %d not found in agent %d", req.GetDatabaseID(), agentID)
|
||||
}
|
||||
|
||||
draft.Database = newDBInfos
|
||||
err = s.DomainSVC.UpdateSingleAgentDraft(ctx, draft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = crossdatabase.DefaultSVC().UnBindDatabase(ctx, &database.UnBindDatabaseToAgentRequest{
|
||||
AgentID: agentID,
|
||||
DraftDatabaseID: req.GetDatabaseID(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &table.BindDatabaseToBotResponse{
|
||||
Code: 0,
|
||||
Msg: "success",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) BindDatabase(ctx context.Context, req *table.BindDatabaseToBotRequest) (*table.BindDatabaseToBotResponse, error) {
|
||||
agentID := req.GetBotID()
|
||||
draft, err := s.ValidateAgentDraftAccess(ctx, agentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dbMap := slices.ToMap(draft.Database, func(d *bot_common.Database) (string, *bot_common.Database) {
|
||||
return d.GetTableId(), d
|
||||
})
|
||||
if _, ok := dbMap[conv.Int64ToStr(req.GetDatabaseID())]; ok {
|
||||
return nil, errorx.New(errno.ErrAgentPermissionCode, errorx.KVf("msg", "database %d already bound to agent %d", req.GetDatabaseID(), agentID))
|
||||
}
|
||||
|
||||
basics := []*database.DatabaseBasic{
|
||||
{
|
||||
ID: req.DatabaseID,
|
||||
TableType: table.TableType_DraftTable,
|
||||
},
|
||||
}
|
||||
|
||||
draftRes, err := crossdatabase.DefaultSVC().MGetDatabase(ctx, &database.MGetDatabaseRequest{
|
||||
Basics: basics,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(draftRes.Databases) == 0 {
|
||||
return nil, fmt.Errorf("database %d not found", req.DatabaseID)
|
||||
}
|
||||
|
||||
draftDatabase := draftRes.Databases[0]
|
||||
|
||||
fields := make([]*bot_common.FieldItem, 0, len(draftDatabase.FieldList))
|
||||
for _, field := range draftDatabase.FieldList {
|
||||
fields = append(fields, &bot_common.FieldItem{
|
||||
Name: ptr.Of(field.Name),
|
||||
Desc: ptr.Of(field.Desc),
|
||||
Type: ptr.Of(bot_common.FieldItemType(field.Type)),
|
||||
MustRequired: ptr.Of(field.MustRequired),
|
||||
AlterId: ptr.Of(field.AlterID),
|
||||
Id: ptr.Of(int64(0)),
|
||||
})
|
||||
}
|
||||
|
||||
bindDB := &bot_common.Database{
|
||||
TableId: ptr.Of(strconv.FormatInt(draftDatabase.ID, 10)),
|
||||
TableName: ptr.Of(draftDatabase.TableName),
|
||||
TableDesc: ptr.Of(draftDatabase.TableDesc),
|
||||
FieldList: fields,
|
||||
RWMode: ptr.Of(bot_common.BotTableRWMode(draftDatabase.RwMode)),
|
||||
}
|
||||
|
||||
if len(draft.Database) == 0 {
|
||||
draft.Database = make([]*bot_common.Database, 0, 1)
|
||||
}
|
||||
draft.Database = append(draft.Database, bindDB)
|
||||
|
||||
err = s.DomainSVC.UpdateSingleAgentDraft(ctx, draft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = crossdatabase.DefaultSVC().BindDatabase(ctx, &database.BindDatabaseToAgentRequest{
|
||||
AgentID: agentID,
|
||||
DraftDatabaseID: req.GetDatabaseID(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &table.BindDatabaseToBotResponse{
|
||||
Code: 0,
|
||||
Msg: "success",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) applyAgentUpdates(target *entity.SingleAgent, patch *bot_common.BotInfoForUpdate) (*entity.SingleAgent, error) {
|
||||
if patch.Name != nil {
|
||||
target.Name = *patch.Name
|
||||
}
|
||||
|
||||
if patch.Description != nil {
|
||||
target.Desc = *patch.Description
|
||||
}
|
||||
|
||||
if patch.IconUri != nil {
|
||||
target.IconURI = *patch.IconUri
|
||||
}
|
||||
|
||||
if patch.OnboardingInfo != nil {
|
||||
target.OnboardingInfo = patch.OnboardingInfo
|
||||
}
|
||||
|
||||
if patch.ModelInfo != nil {
|
||||
target.ModelInfo = patch.ModelInfo
|
||||
}
|
||||
|
||||
if patch.PromptInfo != nil {
|
||||
target.Prompt = patch.PromptInfo
|
||||
}
|
||||
|
||||
if patch.WorkflowInfoList != nil {
|
||||
target.Workflow = patch.WorkflowInfoList
|
||||
}
|
||||
|
||||
if patch.PluginInfoList != nil {
|
||||
target.Plugin = patch.PluginInfoList
|
||||
}
|
||||
|
||||
if patch.Knowledge != nil {
|
||||
target.Knowledge = patch.Knowledge
|
||||
}
|
||||
|
||||
if patch.SuggestReplyInfo != nil {
|
||||
target.SuggestReply = patch.SuggestReplyInfo
|
||||
}
|
||||
|
||||
if patch.BackgroundImageInfoList != nil {
|
||||
target.BackgroundImageInfoList = patch.BackgroundImageInfoList
|
||||
}
|
||||
|
||||
if patch.Agents != nil && len(patch.Agents) > 0 && patch.Agents[0].JumpConfig != nil {
|
||||
target.JumpConfig = patch.Agents[0].JumpConfig
|
||||
}
|
||||
|
||||
if patch.ShortcutSort != nil {
|
||||
target.ShortcutCommand = patch.ShortcutSort
|
||||
}
|
||||
|
||||
if patch.DatabaseList != nil {
|
||||
for _, db := range patch.DatabaseList {
|
||||
if db.PromptDisabled == nil {
|
||||
db.PromptDisabled = ptr.Of(false) // default is false
|
||||
}
|
||||
}
|
||||
target.Database = patch.DatabaseList
|
||||
}
|
||||
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) DeleteAgentDraft(ctx context.Context, req *developer_api.DeleteDraftBotRequest) (*developer_api.DeleteDraftBotResponse, error) {
|
||||
_, err := s.ValidateAgentDraftAccess(ctx, req.GetBotID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.DomainSVC.DeleteAgentDraft(ctx, req.GetSpaceID(), req.GetBotID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.appContext.EventBus.PublishProject(ctx, &searchEntity.ProjectDomainEvent{
|
||||
OpType: searchEntity.Deleted,
|
||||
Project: &searchEntity.ProjectDocument{
|
||||
ID: req.GetBotID(),
|
||||
Type: intelligence.IntelligenceType_Bot,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "publish delete project event failed id = %v , err = %v", req.GetBotID(), err)
|
||||
}
|
||||
|
||||
return &developer_api.DeleteDraftBotResponse{
|
||||
Data: &developer_api.DeleteDraftBotData{},
|
||||
Code: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) singleAgentDraftDo2Vo(ctx context.Context, do *entity.SingleAgent) (*bot_common.BotInfo, error) {
|
||||
vo := &bot_common.BotInfo{
|
||||
BotId: do.AgentID,
|
||||
Name: do.Name,
|
||||
Description: do.Desc,
|
||||
IconUri: do.IconURI,
|
||||
OnboardingInfo: do.OnboardingInfo,
|
||||
ModelInfo: do.ModelInfo,
|
||||
PromptInfo: do.Prompt,
|
||||
PluginInfoList: do.Plugin,
|
||||
Knowledge: do.Knowledge,
|
||||
WorkflowInfoList: do.Workflow,
|
||||
SuggestReplyInfo: do.SuggestReply,
|
||||
CreatorId: do.CreatorID,
|
||||
TaskInfo: &bot_common.TaskInfo{},
|
||||
CreateTime: do.CreatedAt / 1000,
|
||||
UpdateTime: do.UpdatedAt / 1000,
|
||||
BotMode: bot_common.BotMode_SingleMode,
|
||||
BackgroundImageInfoList: do.BackgroundImageInfoList,
|
||||
Status: bot_common.BotStatus_Using,
|
||||
DatabaseList: do.Database,
|
||||
ShortcutSort: do.ShortcutCommand,
|
||||
}
|
||||
|
||||
if do.VariablesMetaID != nil {
|
||||
vars, err := s.appContext.VariablesDomainSVC.GetVariableMetaByID(ctx, *do.VariablesMetaID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if vars != nil {
|
||||
vo.VariableList = vars.ToAgentVariables()
|
||||
}
|
||||
}
|
||||
|
||||
if vo.IconUri != "" {
|
||||
url, err := s.appContext.TosClient.GetObjectUrl(ctx, vo.IconUri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vo.IconUrl = url
|
||||
}
|
||||
|
||||
if vo.ModelInfo == nil || vo.ModelInfo.ModelId == nil {
|
||||
mi, err := s.defaultModelInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vo.ModelInfo = mi
|
||||
}
|
||||
|
||||
return vo, nil
|
||||
}
|
||||
|
||||
func disabledParam(schemaVal *openapi3.Schema) bool {
|
||||
if len(schemaVal.Extensions) == 0 {
|
||||
return false
|
||||
}
|
||||
globalDisable, localDisable := false, false
|
||||
if v, ok := schemaVal.Extensions[plugin.APISchemaExtendLocalDisable]; ok {
|
||||
localDisable = v.(bool)
|
||||
}
|
||||
if v, ok := schemaVal.Extensions[plugin.APISchemaExtendGlobalDisable]; ok {
|
||||
globalDisable = v.(bool)
|
||||
}
|
||||
return globalDisable || localDisable
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) UpdateAgentDraftDisplayInfo(ctx context.Context, req *developer_api.UpdateDraftBotDisplayInfoRequest) (*developer_api.UpdateDraftBotDisplayInfoResponse, error) {
|
||||
uid := ctxutil.GetUIDFromCtx(ctx)
|
||||
if uid == nil {
|
||||
return nil, errorx.New(errno.ErrAgentPermissionCode, errorx.KV("msg", "session required"))
|
||||
}
|
||||
|
||||
_, err := s.ValidateAgentDraftAccess(ctx, req.BotID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
draftInfoDo := &entity.AgentDraftDisplayInfo{
|
||||
AgentID: req.BotID,
|
||||
DisplayInfo: req.DisplayInfo,
|
||||
SpaceID: req.SpaceID,
|
||||
}
|
||||
|
||||
err = s.DomainSVC.UpdateAgentDraftDisplayInfo(ctx, *uid, draftInfoDo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &developer_api.UpdateDraftBotDisplayInfoResponse{
|
||||
Code: 0,
|
||||
Msg: "success",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) GetAgentDraftDisplayInfo(ctx context.Context, req *developer_api.GetDraftBotDisplayInfoRequest) (*developer_api.GetDraftBotDisplayInfoResponse, error) {
|
||||
uid := ctxutil.GetUIDFromCtx(ctx)
|
||||
if uid == nil {
|
||||
return nil, errorx.New(errno.ErrAgentPermissionCode, errorx.KV("msg", "session required"))
|
||||
}
|
||||
|
||||
_, err := s.ValidateAgentDraftAccess(ctx, req.BotID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
draftInfoDo, err := s.DomainSVC.GetAgentDraftDisplayInfo(ctx, *uid, req.BotID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &developer_api.GetDraftBotDisplayInfoResponse{
|
||||
Code: 0,
|
||||
Msg: "success",
|
||||
Data: draftInfoDo.DisplayInfo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) ValidateAgentDraftAccess(ctx context.Context, agentID int64) (*entity.SingleAgent, error) {
|
||||
uid := ctxutil.GetUIDFromCtx(ctx)
|
||||
if uid == nil {
|
||||
uid = ptr.Of(int64(888))
|
||||
// return nil, errorx.New(errno.ErrAgentPermissionCode, errorx.KV("msg", "session uid not found"))
|
||||
}
|
||||
|
||||
do, err := s.DomainSVC.GetSingleAgentDraft(ctx, agentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if do == nil {
|
||||
return nil, errorx.New(errno.ErrAgentPermissionCode, errorx.KVf("msg", "No agent draft(%d) found for the given agent ID", agentID))
|
||||
}
|
||||
|
||||
if do.SpaceID == consts.TemplateSpaceID { // duplicate template, not need check uid permission
|
||||
return do, nil
|
||||
}
|
||||
|
||||
if do.CreatorID != *uid {
|
||||
logs.CtxErrorf(ctx, "user(%d) is not the creator(%d) of the agent draft", *uid, do.CreatorID)
|
||||
|
||||
return do, errorx.New(errno.ErrAgentPermissionCode, errorx.KV("detail", "you are not the agent owner"))
|
||||
}
|
||||
|
||||
return do, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) ListAgentPublishHistory(ctx context.Context, req *developer_api.ListDraftBotHistoryRequest) (*developer_api.ListDraftBotHistoryResponse, error) {
|
||||
resp := &developer_api.ListDraftBotHistoryResponse{}
|
||||
draftAgent, err := s.ValidateAgentDraftAccess(ctx, req.BotID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var connectorID *int64
|
||||
if req.GetConnectorID() != "" {
|
||||
var id int64
|
||||
id, err = conv.StrToInt64(req.GetConnectorID())
|
||||
if err != nil {
|
||||
return nil, errorx.New(errno.ErrAgentInvalidParamCode, errorx.KV("msg", fmt.Sprintf("ConnectorID %v invalidate", *req.ConnectorID)))
|
||||
}
|
||||
|
||||
connectorID = ptr.Of(id)
|
||||
}
|
||||
|
||||
historyList, err := s.DomainSVC.ListAgentPublishHistory(ctx, draftAgent.AgentID, req.PageIndex, req.PageSize, connectorID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uid := ctxutil.MustGetUIDFromCtx(ctx)
|
||||
resp.Data = &developer_api.ListDraftBotHistoryData{}
|
||||
|
||||
for _, v := range historyList {
|
||||
connectorInfos := make([]*developer_api.ConnectorInfo, 0, len(v.ConnectorIds))
|
||||
infos, err := s.appContext.ConnectorDomainSVC.GetByIDs(ctx, v.ConnectorIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, info := range infos {
|
||||
connectorInfos = append(connectorInfos, info.ToVO())
|
||||
}
|
||||
|
||||
creator, err := s.appContext.UserDomainSVC.GetUserProfiles(ctx, v.CreatorID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := ""
|
||||
if v.PublishInfo != nil {
|
||||
info = *v.PublishInfo
|
||||
}
|
||||
|
||||
historyInfo := &developer_api.HistoryInfo{
|
||||
HistoryType: developer_api.HistoryType_FLAG,
|
||||
Version: v.Version,
|
||||
Info: info,
|
||||
CreateTime: conv.Int64ToStr(v.CreatedAt / 1000),
|
||||
ConnectorInfos: connectorInfos,
|
||||
Creator: &developer_api.Creator{
|
||||
ID: v.CreatorID,
|
||||
Name: creator.Name,
|
||||
AvatarURL: creator.IconURL,
|
||||
Self: uid == v.CreatorID,
|
||||
// UserUniqueName: creator.UserUniqueName, // TODO(@fanlv) : user domain 补完以后再改
|
||||
// UserLabel TODO
|
||||
},
|
||||
PublishID: &v.PublishID,
|
||||
}
|
||||
|
||||
resp.Data.HistoryInfos = append(resp.Data.HistoryInfos, historyInfo)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) ReportUserBehavior(ctx context.Context, req *playground.ReportUserBehaviorRequest) (resp *playground.ReportUserBehaviorResponse, err error) {
|
||||
err = s.appContext.EventBus.PublishProject(ctx, &searchEntity.ProjectDomainEvent{
|
||||
OpType: searchEntity.Updated,
|
||||
Project: &searchEntity.ProjectDocument{
|
||||
ID: req.ResourceID,
|
||||
SpaceID: req.SpaceID,
|
||||
Type: intelligence.IntelligenceType_Bot,
|
||||
IsRecentlyOpen: ptr.Of(1),
|
||||
RecentlyOpenMS: ptr.Of(time.Now().UnixMilli()),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "publish updated project event failed id=%v, err=%v", req.ResourceID, err)
|
||||
}
|
||||
|
||||
return &playground.ReportUserBehaviorResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *SingleAgentApplicationService) GetAgentOnlineInfo(ctx context.Context, req *playground.GetBotOnlineInfoReq) (*bot_common.OpenAPIBotInfo, error) {
|
||||
|
||||
uid := ctxutil.MustGetUIDFromApiAuthCtx(ctx)
|
||||
|
||||
connectorID, err := conv.StrToInt64(ptr.From(req.ConnectorID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if connectorID == 0 {
|
||||
connectorID = ctxutil.GetApiAuthFromCtx(ctx).ConnectorID
|
||||
}
|
||||
agentInfo, err := s.DomainSVC.ObtainAgentByIdentity(ctx, &entity.AgentIdentity{
|
||||
AgentID: req.BotID,
|
||||
ConnectorID: connectorID,
|
||||
Version: ptr.From(req.Version),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if agentInfo == nil {
|
||||
logs.CtxErrorf(ctx, "agent(%d) is not exist", req.BotID)
|
||||
return nil, errorx.New(errno.ErrAgentPermissionCode, errorx.KV("msg", "agent not exist"))
|
||||
}
|
||||
if agentInfo.CreatorID != uid {
|
||||
return nil, errorx.New(errno.ErrPromptPermissionCode, errorx.KV("msg", "agent not own"))
|
||||
}
|
||||
combineInfo := &bot_common.OpenAPIBotInfo{
|
||||
BotID: agentInfo.AgentID,
|
||||
Name: agentInfo.Name,
|
||||
Description: agentInfo.Desc,
|
||||
IconURL: agentInfo.IconURI,
|
||||
Version: agentInfo.Version,
|
||||
BotMode: bot_common.BotMode_SingleMode,
|
||||
PromptInfo: agentInfo.Prompt,
|
||||
OnboardingInfo: agentInfo.OnboardingInfo,
|
||||
ModelInfo: agentInfo.ModelInfo,
|
||||
WorkflowInfoList: agentInfo.Workflow,
|
||||
PluginInfoList: agentInfo.Plugin,
|
||||
}
|
||||
|
||||
if agentInfo.IconURI != "" {
|
||||
url, err := s.appContext.TosClient.GetObjectUrl(ctx, agentInfo.IconURI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
combineInfo.IconURL = url
|
||||
}
|
||||
|
||||
if len(agentInfo.ShortcutCommand) > 0 {
|
||||
shortcutInfos, err := s.ShortcutCMDSVC.ListCMD(ctx, &shortcutEntity.ListMeta{
|
||||
ObjectID: agentInfo.AgentID,
|
||||
IsOnline: 1,
|
||||
CommandIDs: slices.Transform(agentInfo.ShortcutCommand, func(s string) int64 {
|
||||
i, _ := conv.StrToInt64(s)
|
||||
return i
|
||||
}),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
combineInfo.ShortcutCommands = make([]*bot_common.ShortcutCommandInfo, 0, len(shortcutInfos))
|
||||
combineInfo.ShortcutCommands = slices.Transform(shortcutInfos, func(si *shortcutEntity.ShortcutCmd) *bot_common.ShortcutCommandInfo {
|
||||
url := ""
|
||||
if si.ShortcutIcon != nil && si.ShortcutIcon.URI != "" {
|
||||
getUrl, e := s.appContext.TosClient.GetObjectUrl(ctx, si.ShortcutIcon.URI)
|
||||
if e == nil {
|
||||
url = getUrl
|
||||
}
|
||||
}
|
||||
|
||||
return &bot_common.ShortcutCommandInfo{
|
||||
ID: si.CommandID,
|
||||
Name: si.CommandName,
|
||||
Description: si.Description,
|
||||
IconURL: url,
|
||||
QueryTemplate: si.TemplateQuery,
|
||||
AgentID: ptr.Of(si.ObjectID),
|
||||
Command: si.ShortcutCommand,
|
||||
Components: slices.Transform(si.Components, func(i *playground.Components) *bot_common.ShortcutCommandComponent {
|
||||
return &bot_common.ShortcutCommandComponent{
|
||||
Name: i.Name,
|
||||
Description: i.Description,
|
||||
Type: i.InputType.String(),
|
||||
ToolParameter: ptr.Of(i.Parameter),
|
||||
Options: i.Options,
|
||||
DefaultValue: ptr.Of(i.DefaultValue.Value),
|
||||
IsHide: i.Hide,
|
||||
}
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
return combineInfo, nil
|
||||
}
|
||||
Reference in New Issue
Block a user