372 lines
12 KiB
Go
372 lines
12 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/Tencent/WeKnora/internal/application/service"
|
|
"github.com/Tencent/WeKnora/internal/errors"
|
|
"github.com/Tencent/WeKnora/internal/logger"
|
|
"github.com/Tencent/WeKnora/internal/types"
|
|
"github.com/Tencent/WeKnora/internal/types/interfaces"
|
|
secutils "github.com/Tencent/WeKnora/internal/utils"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// CustomAgentHandler defines the HTTP handler for custom agent operations
|
|
type CustomAgentHandler struct {
|
|
service interfaces.CustomAgentService
|
|
}
|
|
|
|
// NewCustomAgentHandler creates a new custom agent handler instance
|
|
func NewCustomAgentHandler(service interfaces.CustomAgentService) *CustomAgentHandler {
|
|
return &CustomAgentHandler{
|
|
service: service,
|
|
}
|
|
}
|
|
|
|
// CreateAgentRequest defines the request body for creating an agent
|
|
type CreateAgentRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
Description string `json:"description"`
|
|
Avatar string `json:"avatar"`
|
|
Config types.CustomAgentConfig `json:"config"`
|
|
}
|
|
|
|
// UpdateAgentRequest defines the request body for updating an agent
|
|
type UpdateAgentRequest struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
Avatar string `json:"avatar"`
|
|
Config types.CustomAgentConfig `json:"config"`
|
|
}
|
|
|
|
// CreateAgent godoc
|
|
// @Summary 创建智能体
|
|
// @Description 创建新的自定义智能体
|
|
// @Tags 智能体
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body CreateAgentRequest true "智能体信息"
|
|
// @Success 201 {object} map[string]interface{} "创建的智能体"
|
|
// @Failure 400 {object} errors.AppError "请求参数错误"
|
|
// @Security Bearer
|
|
// @Security ApiKeyAuth
|
|
// @Router /agents [post]
|
|
func (h *CustomAgentHandler) CreateAgent(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
|
|
logger.Info(ctx, "Start creating custom agent")
|
|
|
|
// Parse request body
|
|
var req CreateAgentRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
logger.Error(ctx, "Failed to parse request parameters", err)
|
|
c.Error(errors.NewBadRequestError("Invalid request parameters").WithDetails(err.Error()))
|
|
return
|
|
}
|
|
|
|
// Build agent object
|
|
agent := &types.CustomAgent{
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
Avatar: req.Avatar,
|
|
Config: req.Config,
|
|
}
|
|
|
|
logger.Infof(ctx, "Creating custom agent, name: %s, agent_mode: %s",
|
|
secutils.SanitizeForLog(req.Name), req.Config.AgentMode)
|
|
|
|
// Create agent using the service
|
|
createdAgent, err := h.service.CreateAgent(ctx, agent)
|
|
if err != nil {
|
|
logger.ErrorWithFields(ctx, err, nil)
|
|
if err == service.ErrAgentNameRequired {
|
|
c.Error(errors.NewBadRequestError(err.Error()))
|
|
return
|
|
}
|
|
c.Error(errors.NewInternalServerError(err.Error()))
|
|
return
|
|
}
|
|
|
|
logger.Infof(ctx, "Custom agent created successfully, ID: %s, name: %s",
|
|
secutils.SanitizeForLog(createdAgent.ID), secutils.SanitizeForLog(createdAgent.Name))
|
|
c.JSON(http.StatusCreated, gin.H{
|
|
"success": true,
|
|
"data": createdAgent,
|
|
})
|
|
}
|
|
|
|
// GetAgent godoc
|
|
// @Summary 获取智能体详情
|
|
// @Description 根据ID获取智能体详情
|
|
// @Tags 智能体
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "智能体ID"
|
|
// @Success 200 {object} map[string]interface{} "智能体详情"
|
|
// @Failure 400 {object} errors.AppError "请求参数错误"
|
|
// @Failure 404 {object} errors.AppError "智能体不存在"
|
|
// @Security Bearer
|
|
// @Security ApiKeyAuth
|
|
// @Router /agents/{id} [get]
|
|
func (h *CustomAgentHandler) GetAgent(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
|
|
// Get agent ID from URL parameter
|
|
id := secutils.SanitizeForLog(c.Param("id"))
|
|
if id == "" {
|
|
logger.Error(ctx, "Agent ID is empty")
|
|
c.Error(errors.NewBadRequestError("Agent ID cannot be empty"))
|
|
return
|
|
}
|
|
|
|
agent, err := h.service.GetAgentByID(ctx, id)
|
|
if err != nil {
|
|
logger.ErrorWithFields(ctx, err, map[string]interface{}{
|
|
"agent_id": id,
|
|
})
|
|
if err == service.ErrAgentNotFound {
|
|
c.Error(errors.NewNotFoundError("Agent not found"))
|
|
return
|
|
}
|
|
c.Error(errors.NewInternalServerError(err.Error()))
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"data": agent,
|
|
})
|
|
}
|
|
|
|
// ListAgents godoc
|
|
// @Summary 获取智能体列表
|
|
// @Description 获取当前租户的所有智能体(包括内置智能体)
|
|
// @Tags 智能体
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]interface{} "智能体列表"
|
|
// @Failure 500 {object} errors.AppError "服务器错误"
|
|
// @Security Bearer
|
|
// @Security ApiKeyAuth
|
|
// @Router /agents [get]
|
|
func (h *CustomAgentHandler) ListAgents(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
|
|
// Get all agents for this tenant
|
|
agents, err := h.service.ListAgents(ctx)
|
|
if err != nil {
|
|
logger.ErrorWithFields(ctx, err, nil)
|
|
c.Error(errors.NewInternalServerError(err.Error()))
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"data": agents,
|
|
})
|
|
}
|
|
|
|
// UpdateAgent godoc
|
|
// @Summary 更新智能体
|
|
// @Description 更新智能体的名称、描述和配置
|
|
// @Tags 智能体
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "智能体ID"
|
|
// @Param request body UpdateAgentRequest true "更新请求"
|
|
// @Success 200 {object} map[string]interface{} "更新后的智能体"
|
|
// @Failure 400 {object} errors.AppError "请求参数错误"
|
|
// @Failure 403 {object} errors.AppError "无法修改内置智能体"
|
|
// @Security Bearer
|
|
// @Security ApiKeyAuth
|
|
// @Router /agents/{id} [put]
|
|
func (h *CustomAgentHandler) UpdateAgent(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
|
|
logger.Info(ctx, "Start updating custom agent")
|
|
|
|
// Get agent ID from URL parameter
|
|
id := secutils.SanitizeForLog(c.Param("id"))
|
|
if id == "" {
|
|
logger.Error(ctx, "Agent ID is empty")
|
|
c.Error(errors.NewBadRequestError("Agent ID cannot be empty"))
|
|
return
|
|
}
|
|
|
|
// Parse request body
|
|
var req UpdateAgentRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
logger.Error(ctx, "Failed to parse request parameters", err)
|
|
c.Error(errors.NewBadRequestError("Invalid request parameters").WithDetails(err.Error()))
|
|
return
|
|
}
|
|
|
|
// Build agent object
|
|
agent := &types.CustomAgent{
|
|
ID: id,
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
Avatar: req.Avatar,
|
|
Config: req.Config,
|
|
}
|
|
|
|
logger.Infof(ctx, "Updating custom agent, ID: %s, name: %s",
|
|
secutils.SanitizeForLog(id), secutils.SanitizeForLog(req.Name))
|
|
|
|
// Update the agent
|
|
updatedAgent, err := h.service.UpdateAgent(ctx, agent)
|
|
if err != nil {
|
|
logger.ErrorWithFields(ctx, err, map[string]interface{}{
|
|
"agent_id": id,
|
|
})
|
|
switch err {
|
|
case service.ErrAgentNotFound:
|
|
c.Error(errors.NewNotFoundError("Agent not found"))
|
|
case service.ErrCannotModifyBuiltin:
|
|
c.Error(errors.NewForbiddenError("Cannot modify built-in agent"))
|
|
case service.ErrAgentNameRequired:
|
|
c.Error(errors.NewBadRequestError(err.Error()))
|
|
default:
|
|
c.Error(errors.NewInternalServerError(err.Error()))
|
|
}
|
|
return
|
|
}
|
|
|
|
logger.Infof(ctx, "Custom agent updated successfully, ID: %s", secutils.SanitizeForLog(id))
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"data": updatedAgent,
|
|
})
|
|
}
|
|
|
|
// DeleteAgent godoc
|
|
// @Summary 删除智能体
|
|
// @Description 删除指定的智能体
|
|
// @Tags 智能体
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "智能体ID"
|
|
// @Success 200 {object} map[string]interface{} "删除成功"
|
|
// @Failure 400 {object} errors.AppError "请求参数错误"
|
|
// @Failure 403 {object} errors.AppError "无法删除内置智能体"
|
|
// @Failure 404 {object} errors.AppError "智能体不存在"
|
|
// @Security Bearer
|
|
// @Security ApiKeyAuth
|
|
// @Router /agents/{id} [delete]
|
|
func (h *CustomAgentHandler) DeleteAgent(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
|
|
logger.Info(ctx, "Start deleting custom agent")
|
|
|
|
// Get agent ID from URL parameter
|
|
id := secutils.SanitizeForLog(c.Param("id"))
|
|
if id == "" {
|
|
logger.Error(ctx, "Agent ID is empty")
|
|
c.Error(errors.NewBadRequestError("Agent ID cannot be empty"))
|
|
return
|
|
}
|
|
|
|
logger.Infof(ctx, "Deleting custom agent, ID: %s", secutils.SanitizeForLog(id))
|
|
|
|
// Delete the agent
|
|
err := h.service.DeleteAgent(ctx, id)
|
|
if err != nil {
|
|
logger.ErrorWithFields(ctx, err, map[string]interface{}{
|
|
"agent_id": id,
|
|
})
|
|
switch err {
|
|
case service.ErrAgentNotFound:
|
|
c.Error(errors.NewNotFoundError("Agent not found"))
|
|
case service.ErrCannotDeleteBuiltin:
|
|
c.Error(errors.NewForbiddenError("Cannot delete built-in agent"))
|
|
default:
|
|
c.Error(errors.NewInternalServerError(err.Error()))
|
|
}
|
|
return
|
|
}
|
|
|
|
logger.Infof(ctx, "Custom agent deleted successfully, ID: %s", secutils.SanitizeForLog(id))
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"message": "Agent deleted successfully",
|
|
})
|
|
}
|
|
|
|
// CopyAgent godoc
|
|
// @Summary 复制智能体
|
|
// @Description 复制指定的智能体
|
|
// @Tags 智能体
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "智能体ID"
|
|
// @Success 201 {object} map[string]interface{} "复制成功"
|
|
// @Failure 400 {object} errors.AppError "请求参数错误"
|
|
// @Failure 404 {object} errors.AppError "智能体不存在"
|
|
// @Security Bearer
|
|
// @Security ApiKeyAuth
|
|
// @Router /agents/{id}/copy [post]
|
|
func (h *CustomAgentHandler) CopyAgent(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
|
|
logger.Info(ctx, "Start copying custom agent")
|
|
|
|
// Get agent ID from URL parameter
|
|
id := secutils.SanitizeForLog(c.Param("id"))
|
|
if id == "" {
|
|
logger.Error(ctx, "Agent ID is empty")
|
|
c.Error(errors.NewBadRequestError("Agent ID cannot be empty"))
|
|
return
|
|
}
|
|
|
|
logger.Infof(ctx, "Copying custom agent, ID: %s", secutils.SanitizeForLog(id))
|
|
|
|
// Copy the agent
|
|
copiedAgent, err := h.service.CopyAgent(ctx, id)
|
|
if err != nil {
|
|
logger.ErrorWithFields(ctx, err, map[string]interface{}{
|
|
"agent_id": id,
|
|
})
|
|
switch err {
|
|
case service.ErrAgentNotFound:
|
|
c.Error(errors.NewNotFoundError("Agent not found"))
|
|
default:
|
|
c.Error(errors.NewInternalServerError(err.Error()))
|
|
}
|
|
return
|
|
}
|
|
|
|
logger.Infof(ctx, "Custom agent copied successfully, source ID: %s, new ID: %s",
|
|
secutils.SanitizeForLog(id), secutils.SanitizeForLog(copiedAgent.ID))
|
|
c.JSON(http.StatusCreated, gin.H{
|
|
"success": true,
|
|
"data": copiedAgent,
|
|
})
|
|
}
|
|
|
|
// GetPlaceholders godoc
|
|
// @Summary 获取占位符定义
|
|
// @Description 获取所有可用的提示词占位符定义,按字段类型分组
|
|
// @Tags 智能体
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]interface{} "占位符定义"
|
|
// @Security Bearer
|
|
// @Security ApiKeyAuth
|
|
// @Router /agents/placeholders [get]
|
|
func (h *CustomAgentHandler) GetPlaceholders(c *gin.Context) {
|
|
// Return all placeholder definitions grouped by field type
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"data": gin.H{
|
|
"all": types.AllPlaceholders(),
|
|
"system_prompt": types.PlaceholdersByField(types.PromptFieldSystemPrompt),
|
|
"agent_system_prompt": types.PlaceholdersByField(types.PromptFieldAgentSystemPrompt),
|
|
"context_template": types.PlaceholdersByField(types.PromptFieldContextTemplate),
|
|
"rewrite_system_prompt": types.PlaceholdersByField(types.PromptFieldRewriteSystemPrompt),
|
|
"rewrite_prompt": types.PlaceholdersByField(types.PromptFieldRewritePrompt),
|
|
"fallback_prompt": types.PlaceholdersByField(types.PromptFieldFallbackPrompt),
|
|
},
|
|
})
|
|
}
|