734 lines
22 KiB
Go
734 lines
22 KiB
Go
/*
|
||
* 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
|
||
}
|