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): error code
 | |
| 	}
 | |
| 
 | |
| 	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): error code
 | |
| 	}
 | |
| 
 | |
| 	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): Change the user domain after it is completed
 | |
| 				// 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
 | |
| }
 |